misc.cc 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2014 Bryan Drewery
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. /*
  21. * misc.c -- handles:
  22. * split() maskhost() dumplots() daysago() days() daysdur()
  23. * queueing output for the bot (msg and help)
  24. * resync buffers for sharebots
  25. * motd display and %var substitution
  26. *
  27. */
  28. #include "common.h"
  29. #include "misc.h"
  30. #include "settings.h"
  31. #include "binary.h"
  32. #include "rfc1459.h"
  33. #include "botnet.h"
  34. #include "misc_file.h"
  35. #include "egg_timer.h"
  36. #include "dcc.h"
  37. #include "users.h"
  38. #include "shell.h"
  39. #include "main.h"
  40. #include "debug.h"
  41. #include "dccutil.h"
  42. #include "chanprog.h"
  43. #include "color.h"
  44. #include "botmsg.h"
  45. #include "bg.h"
  46. #include "chan.h"
  47. #include "tandem.h"
  48. #include "src/mod/server.mod/server.h"
  49. #include "src/mod/irc.mod/irc.h"
  50. #include "src/mod/channels.mod/channels.h"
  51. #include "userrec.h"
  52. #include "stat.h"
  53. #include "net.h"
  54. #include "EncryptedStream.h"
  55. #include <bdlib/src/String.h>
  56. #include <bdlib/src/Stream.h>
  57. #include <sys/wait.h>
  58. #include <stdarg.h>
  59. #include <sys/types.h>
  60. #include <signal.h>
  61. int server_lag = 0; /* GUESS! */
  62. bool use_invites = 0;
  63. bool use_exempts = 0;
  64. /*
  65. * Misc functions
  66. */
  67. /* low-level stuff for other modules
  68. */
  69. size_t my_strcpy(char *a, const char *b)
  70. {
  71. const char *c = b;
  72. while (*b)
  73. *a++ = *b++;
  74. *a = *b;
  75. return b - c;
  76. }
  77. /* Split first word off of rest and put it in first
  78. */
  79. void splitc(char *first, char *rest, char divider)
  80. {
  81. char *p = strchr(rest, divider);
  82. if (p == NULL) {
  83. if (first != rest && first)
  84. first[0] = 0;
  85. return;
  86. }
  87. *p = 0;
  88. if (first != NULL)
  89. strcpy(first, rest);
  90. if (first != rest)
  91. /* In most circumstances, strcpy with src and dst being the same buffer
  92. * can produce undefined results. We're safe here, as the src is
  93. * guaranteed to be at least 2 bytes higher in memory than dest. <Cybah>
  94. */
  95. strcpy(rest, p + 1);
  96. }
  97. /* As above, but lets you specify the 'max' number of bytes (EXCLUDING the
  98. * terminating null).
  99. *
  100. * Example of use:
  101. *
  102. * char buf[HANDLEN + 1];
  103. *
  104. * splitcn(buf, input, "@", HANDLEN);
  105. *
  106. * <Cybah>
  107. */
  108. void splitcn(char *first, char *rest, char divider, size_t max)
  109. {
  110. char *p = strchr(rest, divider);
  111. if (p == NULL) {
  112. if (first != rest && first)
  113. first[0] = 0;
  114. return;
  115. }
  116. *p = 0;
  117. if (first != NULL)
  118. strlcpy(first, rest, max);
  119. if (first != rest)
  120. /* In most circumstances, strcpy with src and dst being the same buffer
  121. * can produce undefined results. We're safe here, as the src is
  122. * guaranteed to be at least 2 bytes higher in memory than dest. <Cybah>
  123. */
  124. strcpy(rest, p + 1);
  125. }
  126. char *splitnick(char **blah)
  127. {
  128. char *p = NULL, *q = *blah;
  129. p = strchr(*blah, '!');
  130. if (p) {
  131. *p = 0;
  132. *blah = p + 1;
  133. return q;
  134. }
  135. return "";
  136. }
  137. int remove_crlf(char *line)
  138. {
  139. char *p = NULL;
  140. int removed = 0;
  141. if ((p = strchr(line, '\n'))) {
  142. *p = 0;
  143. removed++;
  144. }
  145. if ((p = strchr(line, '\r'))) {
  146. *p = 0;
  147. removed++;
  148. }
  149. return removed;
  150. }
  151. int remove_crlf_r(char *line)
  152. {
  153. char *p = NULL;
  154. int removed = 0;
  155. if ((p = strrchr(line, '\n'))) {
  156. *p = 0;
  157. removed++;
  158. }
  159. if ((p = strrchr(line, '\r'))) {
  160. *p = 0;
  161. removed++;
  162. }
  163. return removed;
  164. }
  165. char *newsplit(char **rest, char delim, bool trim)
  166. {
  167. if (!rest)
  168. return *rest = "";
  169. char *o = *rest, *r = NULL;
  170. while (*o == delim)
  171. ++o;
  172. r = o;
  173. while (*o && (*o != delim))
  174. ++o;
  175. if (*o)
  176. *o++ = 0;
  177. /* Trim whitespace */
  178. if (trim) {
  179. while (*o == ' ')
  180. ++o;
  181. }
  182. *rest = o;
  183. return r;
  184. }
  185. /* maskhost(), modified to support custom mask types, as defined
  186. * by mIRC.
  187. * Does not require a proper hostmask in 's'. Accepts any strings,
  188. * including empty ones and attempts to provide meaningful results.
  189. *
  190. * Strings containing no '@' character will be parsed as if the
  191. * whole string is a host.
  192. * Strings containing no '!' character will be interpreted as if
  193. * there is no nick.
  194. * '!' as a nick/user separator must precede any '@' characters.
  195. * Otherwise it will be considered a part of the host.
  196. * Supported types are listed in tcl-commands.doc in the maskhost
  197. * command section. Type 3 resembles the older maskhost() most closely.
  198. *
  199. * Specific examples (with type=3):
  200. *
  201. * "nick!user@is.the.lamest.bg" -> *!*user@*.the.lamest.bg (ccTLD)
  202. * "nick!user@is.the.lamest.com" -> *!*user@*.lamest.com (gTLD)
  203. * "lamest.example" -> *!*@lamest.example
  204. * "whatever@lamest.example" -> *!*whatever@lamest.example
  205. * "com.example@user!nick" -> *!*com.example@user!nick
  206. * "!" -> *!*@!
  207. * "@" -> *!*@*
  208. * "" -> *!*@*
  209. * "abc!user@2001:db8:618:5c0:263:15:dead:babe"
  210. * -> *!*user@2001:db8:618:5c0:263:15:dead:*
  211. * "abc!user@0:0:0:0:0:ffff:1.2.3.4"
  212. * -> *!*user@0:0:0:0:0:ffff:1.2.3.*
  213. */
  214. void maskaddr(const char *s, char *nw, int type)
  215. {
  216. int d = type % 5, num = 1;
  217. const char *u = NULL, *h = NULL, *p = NULL;
  218. /* Look for user and host.. */
  219. if ((u = strchr(s, '!')))
  220. h = strchr(u, '@');
  221. if (!h)
  222. h = strchr(s, '@');
  223. /* Print nick if required and available */
  224. if (!u || (type % 10) < 5)
  225. *nw++ = '*';
  226. else {
  227. strncpy(nw, s, u - s);
  228. nw += u - s;
  229. }
  230. *nw++ = '!';
  231. /* Write user if required and available */
  232. u = (u ? u + 1 : s);
  233. if (!h || (d == 2) || (d == 4))
  234. *nw++ = '*';
  235. else {
  236. if (d) {
  237. *nw++ = '*';
  238. if (strchr("~+-^=", *u))
  239. u++; /* trim leading crap */
  240. /*
  241. * Take last 9 chars to avoid running up against 10-char limit for
  242. * username on ratbox. The older eggdrop code used this limit as well.
  243. */
  244. while (h - u > 9)
  245. u++;
  246. }
  247. strncpy(nw, u, h - u);
  248. nw += h - u;
  249. }
  250. *nw++ = '@';
  251. /* The rest is for the host */
  252. h = (h ? h + 1 : s);
  253. for (p = h; *p; p++) /* hostname? */
  254. if ((*p > '9' || *p < '0') && *p != '.') {
  255. num = 0;
  256. break;
  257. }
  258. p = strrchr(h, ':'); /* IPv6? */
  259. /* Mask out after the last colon/dot */
  260. if (p && d > 2) {
  261. if ((u = strrchr(p, '.')))
  262. p = u;
  263. strncpy(nw, h, ++p - h);
  264. nw += p - h;
  265. strcpy(nw, "*");
  266. } else if (!p && !num && type >= 10) {
  267. /* we have a hostname and type
  268. requires us to replace numbers */
  269. num = 0;
  270. for (p = h; *p; p++) {
  271. if (*p < '0' || *p > '9') {
  272. *nw++ = *p;
  273. num = 0;
  274. } else {
  275. if (type < 20)
  276. *nw++ = '?';
  277. else if (!num) {
  278. *nw++ = '*';
  279. num = 1; /* place only one '*'
  280. per numeric sequence */
  281. }
  282. }
  283. }
  284. *nw = 0;
  285. } else if (d > 2 && (p = strrchr(h, '.'))) {
  286. if (num) { /* IPv4 */
  287. strncpy(nw, h, p - h);
  288. nw += p - h;
  289. strcpy(nw, ".*");
  290. return;
  291. }
  292. for (u = h, d = 0; (u = strchr(++u, '.')); d++) ;
  293. if (d < 2) { /* types < 2 don't mask the host */
  294. strcpy(nw, h);
  295. return;
  296. }
  297. u = strchr(h, '.');
  298. if (d > 3 || (d == 3 && strlen(p) > 3))
  299. u = strchr(++u, '.'); /* ccTLD or not? Look above. */
  300. simple_sprintf(nw, "*%s", u);
  301. } else if (!*h) {
  302. /* take care if the mask is empty or contains only '@' */
  303. strcpy(nw, "*");
  304. } else
  305. strcpy(nw, h);
  306. }
  307. /* Convert an interval (in seconds) to one of:
  308. * "19 days ago", "1 day ago", "18:12"
  309. */
  310. void daysago(time_t mynow, time_t then, char *out, size_t outsiz)
  311. {
  312. if (mynow - then > 86400) {
  313. int mydays = (mynow - then) / 86400;
  314. simple_snprintf(out, outsiz, "%d day%s ago", mydays, (mydays == 1) ? "" : "s");
  315. return;
  316. }
  317. strftime(out, 6, "%H:%M", gmtime(&then));
  318. }
  319. /* Convert an interval (in seconds) to one of:
  320. * "in 19 days", "in 1 day", "at 18:12"
  321. */
  322. void days(time_t mynow, time_t then, char *out, size_t outsiz)
  323. {
  324. if (mynow - then > 86400) {
  325. int mydays = (mynow - then) / 86400;
  326. simple_snprintf(out, outsiz, "in %d day%s", mydays, (mydays == 1) ? "" : "s");
  327. return;
  328. }
  329. strftime(out, 9, "at %H:%M", gmtime(&now));
  330. }
  331. /* Convert an interval (in seconds) to one of:
  332. * "for 19 days", "for 1 day", "for 09:10"
  333. */
  334. void daysdur(time_t mynow, time_t then, char *out, size_t outsiz, bool useFor)
  335. {
  336. size_t startIndex = 0;
  337. out[0] = 0;
  338. if (useFor) {
  339. strlcpy(out, "for ", outsiz);
  340. startIndex = 4;
  341. }
  342. if (mynow - then > 86400) {
  343. int mydays = (mynow - then) / 86400;
  344. simple_snprintf(&out[startIndex], outsiz - startIndex, "%d day%s", mydays, (mydays == 1) ? "" : "s");
  345. return;
  346. }
  347. char s[81] = "";
  348. mynow -= then;
  349. int hrs = (int) (mynow / 3600);
  350. int mins = (int) ((mynow - (hrs * 3600)) / 60);
  351. simple_snprintf(s, sizeof(s), "%02d:%02d", hrs, mins);
  352. strlcat(out, s, outsiz);
  353. }
  354. /* show l33t banner */
  355. static const char *wbanner(void) {
  356. /*
  357. __ __ __
  358. __ _ ______________ |__|/ |_| |__
  359. \ \/ \/ /\_ __ \__ \ | \ _\ | \
  360. \ / | | \// __ \| || | | \ \
  361. \/\_/ |__| (____ /__||__| |___| /
  362. \/ \/
  363. */
  364. return STR(" __ __ __\n__ _ ______________ |__|/ |_| |__\n\\ \\/ \\/ /\\_ __ \\__ \\ | \\ _\\ | \\\n \\ / | | \\// __ \\| || | | \\ \\\n \\/\\_/ |__| (____ /__||__| |___| /\n \\/ \\/\n");
  365. }
  366. void show_banner(int idx)
  367. {
  368. /* we use sock so that colors aren't applied to banner */
  369. if (dcc[idx].status & STAT_BANNER)
  370. dumplots(-dcc[idx].sock, "", wbanner());
  371. dprintf(idx, " \n");
  372. dprintf(-dcc[idx].sock, STR(" -------------------------------------------------------- \n"));
  373. dprintf(-dcc[idx].sock, STR("| - http://wraith.botpack.net/ - |\n"));
  374. dprintf(-dcc[idx].sock, STR("| Get Shell/Irc/Web hosting @ http://www.xzibition.com |\n"));
  375. dprintf(-dcc[idx].sock, STR("| Help support wraith development by signing up. |\n"));
  376. dprintf(-dcc[idx].sock, STR("| Use coupon code 'wraith' for 30%% off lifetime |\n"));
  377. dprintf(-dcc[idx].sock, STR(" -------------------------------------------------------- \n"));
  378. dprintf(idx, " \n");
  379. }
  380. /* show motd to dcc chatter */
  381. void show_motd(int idx)
  382. {
  383. if (motd[0]) {
  384. char *who = NULL, *buf = NULL, *buf_ptr = NULL, date[50] = "";
  385. time_t when;
  386. buf = buf_ptr = strdup(motd);
  387. who = newsplit(&buf);
  388. when = atoi(newsplit(&buf));
  389. strftime(date, sizeof date, "%c %Z", gmtime(&when));
  390. dprintf(idx, "Motd set by %s%s%s (%s)\n", BOLD(idx), who, BOLD_END(idx), date);
  391. dumplots(idx, "* ", replace(buf, "\\n", "\n"));
  392. dprintf(idx, " \n");
  393. free(buf_ptr);
  394. } else
  395. dprintf(idx, "Motd: none\n");
  396. }
  397. void show_channels(int idx, char *handle)
  398. {
  399. struct userrec *u = NULL;
  400. size_t maxChannelLength = 0;
  401. bd::Array<bd::String> channelNames;
  402. bd::HashTable<bd::String, struct chanset_t*> channels;
  403. bd::String group;
  404. if (handle && handle[0] != '%') {
  405. u = get_user_by_handle(userlist, handle);
  406. } else {
  407. u = dcc[idx].user;
  408. if (handle && handle[0] == '%') {
  409. group = handle + 1;
  410. }
  411. }
  412. for (struct chanset_t* chan = chanset; chan; chan = chan->next) {
  413. struct flag_record fr = { FR_CHAN | FR_GLOBAL, 0, 0, 0 };
  414. const bd::String chname(chan->dname);
  415. // If a group was passed, ensure it matches
  416. if (group.length() && chan->groups->find(group) == chan->groups->npos) {
  417. continue;
  418. }
  419. get_user_flagrec(u, &fr, chan->dname);
  420. if (group.length() || real_chk_op(fr, chan, 0)) {
  421. if (maxChannelLength < chname.length()) {
  422. maxChannelLength = chname.length();
  423. }
  424. channelNames << chname;
  425. channels[chname] = chan;
  426. }
  427. }
  428. if (channelNames.length()) {
  429. char format[120] = "";
  430. simple_snprintf(format, sizeof(format), " %%c%%-%zus %%-s%%-s%%-s%%-s%%-s%%-s\n", (maxChannelLength+2));
  431. if (group.length()) {
  432. dprintf(idx, "group '%s' is in %zu channel%s:\n", group.c_str(), channelNames.length(), (channelNames.length() > 1) ? "s" : "");
  433. } else {
  434. dprintf(idx, "%s %s access to %zu channel%s:\n", handle ? u->handle : "You", handle ? "has" : "have", channelNames.length(), (channelNames.length() > 1) ? "s" : "");
  435. }
  436. for (size_t i = 0; i < channelNames.length(); ++i) {
  437. const bd::String chname(channelNames[i]);
  438. const struct chanset_t* chan = channels[chname];
  439. dprintf(idx, format, !conf.bot->hub && me_op(chan) ? '@' : ' ', chan->dname, ((conf.bot->hub && channel_inactive(chan)) || (!conf.bot->hub && !shouldjoin(chan))) ? "(inactive) " : "",
  440. channel_privchan(chan) ? "(private) " : "", chan->manop ? "(no manop) " : "",
  441. channel_bitch(chan) && !channel_botbitch(chan) ? "(bitch) " : channel_botbitch(chan) ? "(botbitch) " : "",
  442. channel_closed(chan) ? "(closed) " : "", channel_backup(chan) ? "(backup)" : "");
  443. }
  444. } else {
  445. if (group.length()) {
  446. dprintf(idx, "No channels found for group '%s'\n", group.c_str());
  447. } else {
  448. dprintf(idx, "%s %s not have access to any channels.\n", handle ? u->handle : "You", handle ? "does" : "do");
  449. }
  450. }
  451. }
  452. /* Create a string with random letters and digits
  453. */
  454. void make_rand_str(char *s, size_t len, bool special)
  455. {
  456. int r = 0;
  457. size_t j = 0;
  458. for (j = 0; j < len; j++) {
  459. r = randint(special ? 4 : 3);
  460. if (r == 0)
  461. s[j] = '0' + randint(10);
  462. else if (r == 1)
  463. s[j] = 'a' + randint(26);
  464. else if (r == 2)
  465. s[j] = 'A' + randint(26);
  466. else if (r == 3)
  467. s[j] = RANDSPECIAL[randint(RANDSPECIALLEN)];
  468. if (j && strchr(BADREPEATEDRAND, s[j]) && s[j] == s[j - 1]) {
  469. while (s[j] == s[j - 1])
  470. s[j] = 'A' + randint(26);
  471. }
  472. }
  473. if (strchr(BADPASSCHARS, s[0]))
  474. s[0] = 'a' + randint(26);
  475. s[len] = '\0';
  476. }
  477. /* Return an allocated buffer which contains a copy of the string
  478. * 'str', with all 'div' characters escaped by 'mask'. 'mask'
  479. * characters are escaped too.
  480. *
  481. * Remember to free the returned memory block.
  482. */
  483. char *str_escape(const char *str, const char divc, const char mask)
  484. {
  485. const size_t len = strlen(str);
  486. size_t buflen = (2 * len), blen = 0;
  487. char *buf = NULL, *b = NULL;
  488. const char *s = NULL;
  489. b = buf = (char *) calloc(1, buflen + 1);
  490. for (s = str; *s; s++) {
  491. /* Resize buffer. */
  492. if ((buflen - blen) <= 3) {
  493. buflen <<= 1; /* * 2 */
  494. buf = (char *) realloc(buf, buflen + 1);
  495. if (!buf)
  496. return NULL;
  497. b = buf + blen;
  498. }
  499. if (*s == divc || *s == mask) {
  500. simple_snprintf(b, buflen, "%c%02x", mask, *s);
  501. b += 3;
  502. blen += 3;
  503. } else {
  504. *(b++) = *s;
  505. blen++;
  506. }
  507. }
  508. *b = 0;
  509. return buf;
  510. }
  511. /* Search for a certain character 'div' in the string 'str', while
  512. * ignoring escaped characters prefixed with 'mask'.
  513. *
  514. * The string
  515. *
  516. * "\\3a\\5c i am funny \\3a):further text\\5c):oink"
  517. *
  518. * as str, '\\' as mask and ':' as div would change the str buffer
  519. * to
  520. *
  521. * ":\\ i am funny :)"
  522. *
  523. * and return a pointer to "further text\\5c):oink".
  524. *
  525. * NOTE: If you look carefully, you'll notice that strchr_unescape()
  526. * behaves differently than strchr().
  527. */
  528. char *strchr_unescape(char *str, const char divc, const char esc_char)
  529. {
  530. char buf[3] = "";
  531. char *s = NULL, *p = NULL;
  532. for (s = p = str; *s; s++, p++) {
  533. if (*s == esc_char) { /* Found escape character. */
  534. /* Convert code to character. */
  535. buf[0] = s[1], buf[1] = s[2];
  536. *p = (unsigned char) strtol(buf, NULL, 16);
  537. s += 2;
  538. } else if (*s == divc) {
  539. *p = *s = 0;
  540. return (s + 1); /* Found searched for character. */
  541. } else
  542. *p = *s;
  543. }
  544. *p = 0;
  545. return NULL;
  546. }
  547. char s1_16[3] = "",s2_6[3] = "",s2_7[3] = "";
  548. /* As strchr_unescape(), but converts the complete string, without
  549. * searching for a specific delimiter character.
  550. */
  551. void str_unescape(char *str, const char esc_char)
  552. {
  553. strchr_unescape(str, 0, esc_char);
  554. return;
  555. }
  556. /* Is every character in a string a digit? */
  557. int str_isdigit(const char *str)
  558. {
  559. if (!str || (str && !*str))
  560. return 0;
  561. if (*str == '-' && str[1])
  562. str++;
  563. for(; *str; ++str) {
  564. if (!egg_isdigit(*str))
  565. return 0;
  566. }
  567. return 1;
  568. }
  569. /* Kills the bot. s1 is the reason shown to other bots,
  570. * s2 the reason shown on the partyline. (Sup 25Jul2001)
  571. */
  572. void kill_bot(char *s1, char *s2)
  573. {
  574. write_userfile(-1);
  575. if (!conf.bot->hub)
  576. server_die();
  577. chatout("*** %s\n", s1);
  578. botnet_send_chat(-1, conf.bot->nick, s1);
  579. botnet_send_bye(s2);
  580. fatal(s2, 0);
  581. }
  582. void
  583. readsocks(const char *fname)
  584. {
  585. /* Don't bother setting this if a hub
  586. ... it is only intended to prevent parting channels (in bot_shouldjoin())
  587. */
  588. if (!conf.bot->hub)
  589. restarting = 1;
  590. char *_botname = NULL, *ip4 = NULL, *ip6 = NULL,
  591. *_origbotname = NULL, *_jupenick = NULL;
  592. time_t old_buildts = 0, _server_online = 0;
  593. bool cached_005 = 0;
  594. const char salt1[] = SALT1;
  595. EncryptedStream stream(salt1);
  596. stream.loadFile(fname);
  597. bd::String str, type;
  598. reset_chans = 0;
  599. while (stream.tell() < stream.length()) {
  600. str = stream.getline().chomp();
  601. dprintf(DP_DEBUG, "read line: %s\n", str.c_str());
  602. type = newsplit(str);
  603. if (type == STR("-dcc"))
  604. dprintf(DP_DEBUG, STR("Added dcc: %d\n"), dcc_read(stream));
  605. else if (type == STR("-sock"))
  606. dprintf(DP_DEBUG, STR("Added fd: %d\n"), sock_read(stream));
  607. else if (type == STR("+online_since"))
  608. online_since = strtol(str.c_str(), NULL, 10);
  609. else if (type == STR("+server_online"))
  610. _server_online = strtol(str.c_str(), NULL, 10);
  611. else if (type == STR("+server_floodless"))
  612. floodless = 1;
  613. else if (type == STR("+in_deaf"))
  614. in_deaf = 1;
  615. else if (type == STR("+in_callerid"))
  616. in_callerid = 1;
  617. else if (type == STR("+chan")) {
  618. bd::String chname = str;
  619. channel_add(NULL, chname.c_str(), NULL);
  620. struct chanset_t* chan = findchan_by_dname(chname.c_str());
  621. strlcpy(chan->name, chan->dname, sizeof(chan->name));
  622. chan->status = chan->ircnet_status = 0;
  623. chan->ircnet_status |= CHAN_PEND;
  624. reset_chans = 2;
  625. }
  626. else if (type == STR("+buildts"))
  627. old_buildts = strtol(str.c_str(), NULL, 10);
  628. else if (type == STR("+botname"))
  629. _botname = str.dup();
  630. else if (type == STR("+origbotname"))
  631. _origbotname = str.dup();
  632. else if (type == STR("+jupenick"))
  633. _jupenick = str.dup();
  634. else if (type == STR("+rolls"))
  635. rolls = atoi(str.c_str());
  636. else if (type == STR("+altnick_char"))
  637. altnick_char = str[0];
  638. else if (type == STR("+burst"))
  639. burst = atoi(str.c_str());
  640. else if (type == STR("+flood_count"))
  641. flood_count = atoi(str.c_str());
  642. else if (type == STR("+my_cookie_counter")) {
  643. my_cookie_counter = strtol(str.c_str(), NULL, 10);
  644. my_cookie_counter += 100; // Increase to avoid race conditions
  645. }
  646. else if (type == STR("+ip4"))
  647. ip4 = str.dup();
  648. else if (type == STR("+ip6"))
  649. ip6 = str.dup();
  650. else if (type == STR("+serv_cache")) {
  651. if (!cached_005 && str.find(STR("005")))
  652. cached_005 = 1;
  653. dprintf(DP_CACHE, "%s", str.c_str());
  654. }
  655. }
  656. restart_time = now;
  657. if (old_buildts && buildts > old_buildts)
  658. restart_was_update = 1;
  659. tell_dcc(DP_DEBUG);
  660. tell_netdebug(DP_DEBUG);
  661. unlink(fname);
  662. /* server_online is not yet set so these will safely not send NICK. */
  663. if (_origbotname) {
  664. var_set_by_name(conf.bot->nick, "nick", _origbotname);
  665. }
  666. if (_jupenick) {
  667. var_set_by_name(conf.bot->nick, "jupenick", _jupenick);
  668. }
  669. if (servidx >= 0) {
  670. char nserv[50] = "";
  671. if ((ip4 && ip6) && (strcmp(ip4, myipstr(AF_INET)) || strcmp(ip6, myipstr(AF_INET6)))) {
  672. if (tands > 0) { /* We're not linked yet.. but for future */
  673. botnet_send_chat(-1, conf.bot->nick, STR("IP changed."));
  674. botnet_send_bye(STR("IP changed."));
  675. }
  676. fatal("brb", 1);
  677. } else if (conf.bot->hub) {
  678. // I became a hub during restart... disconnect from IRC.
  679. if (tands > 0) { /* We're not linked yet.. but for future */
  680. botnet_send_chat(-1, conf.bot->nick, STR("Changing to HUB."));
  681. botnet_send_bye(STR("Changing to HUB."));
  682. }
  683. nuke_server("emoquit");
  684. } else {
  685. simple_snprintf(nserv, sizeof(nserv), "%s:%d", dcc[servidx].host, dcc[servidx].port);
  686. add_server(nserv);
  687. curserv = 0;
  688. keepnick = 0; /* Wait to change nicks until relinking, fixes nick/jupenick switching issues during restart */
  689. reset_flood();
  690. if (!_server_online)
  691. _server_online = now;
  692. server_online = _server_online;
  693. rehash_server(dcc[servidx].host, _botname);
  694. if (cached_005)
  695. replay_cache(servidx, NULL);
  696. else
  697. dprintf(DP_DUMP, "VERSION\n");
  698. if (!reset_chans)
  699. reset_chans = 1;
  700. }
  701. }
  702. delete[] _botname;
  703. delete[] _origbotname;
  704. delete[] _jupenick;
  705. delete[] ip4;
  706. delete[] ip6;
  707. if (socksfile)
  708. free(socksfile);
  709. }
  710. /* Update system code
  711. */
  712. void
  713. restart(int idx)
  714. {
  715. const char *reason = updating ? STR("Updating...") : STR("Restarting...");
  716. Tempfile *socks = new Tempfile("socks");
  717. int fd = 0;
  718. sdprintf("%s", reason);
  719. if (tands > 0) {
  720. botnet_send_chat(-1, conf.bot->nick, (char *) reason);
  721. botnet_send_bye(reason);
  722. }
  723. /* Stop sharing to prevent writing LASTON to lostdcc() DCC_BOT sockets. */
  724. noshare = 1;
  725. /* kill all connections except STDOUT/server */
  726. for (fd = 0; fd < dcc_total; fd++) {
  727. if (dcc[fd].type && dcc[fd].type != &SERVER_SOCKET && dcc[fd].sock != STDOUT) {
  728. if (dcc[fd].sock >= 0)
  729. killsock(dcc[fd].sock);
  730. lostdcc(fd);
  731. }
  732. }
  733. const char salt1[] = SALT1;
  734. EncryptedStream stream(salt1);
  735. /* write out all leftover dcc[] entries */
  736. for (fd = 0; fd < dcc_total; fd++)
  737. if (dcc[fd].type && dcc[fd].sock != STDOUT)
  738. dcc_write(stream, fd);
  739. /* write out all leftover socklist[] entries */
  740. for (fd = 0; fd < MAXSOCKS; fd++)
  741. if (socklist[fd].sock != STDOUT)
  742. sock_write(stream, fd);
  743. if (server_online) {
  744. if (botname[0])
  745. stream << bd::String::printf(STR("+botname %s\n"), botname);
  746. if (origbotname[0])
  747. stream << bd::String::printf(STR("+origbotname %s\n"), origbotname);
  748. if (jupenick[0])
  749. stream << bd::String::printf(STR("+jupenick %s\n"), jupenick);
  750. if (rolls)
  751. stream << bd::String::printf(STR("+rolls %d\n"), rolls);
  752. if (altnick_char)
  753. stream << bd::String::printf(STR("+altnick_char %c\n"), altnick_char);
  754. if (burst)
  755. stream << bd::String::printf(STR("+burst %d\n"), burst);
  756. if (flood_count)
  757. stream << bd::String::printf(STR("+flood_count %d\n"), flood_count);
  758. if (my_cookie_counter)
  759. stream << bd::String::printf(STR("+my_cookie_counter %lu\n"), my_cookie_counter);
  760. stream << bd::String::printf(STR("+server_online %li\n"), (long)server_online);
  761. }
  762. stream << bd::String::printf(STR("+online_since %li\n"), (long)online_since);
  763. if (floodless)
  764. stream << bd::String::printf(STR("+server_floodless %d\n"), floodless);
  765. if (in_deaf)
  766. stream << bd::String::printf(STR("+in_deaf\n"));
  767. if (in_callerid)
  768. stream << bd::String::printf(STR("+in_callerid\n"));
  769. for (struct chanset_t *chan = chanset; chan; chan = chan->next)
  770. if (shouldjoin(chan) && (channel_active(chan) || channel_pending(chan)))
  771. stream << bd::String::printf(STR("+chan %s\n"), chan->dname);
  772. stream << bd::String::printf(STR("+buildts %li\n"), (long)buildts);
  773. stream << bd::String::printf(STR("+ip4 %s\n"), myipstr(AF_INET));
  774. stream << bd::String::printf(STR("+ip6 %s\n"), myipstr(AF_INET6));
  775. replay_cache(-1, &stream);
  776. stream.writeFile(socks->fd);
  777. socks->my_close();
  778. write_userfile(idx);
  779. /*
  780. if (server_online) {
  781. do_chanset(NULL, NULL, STR("+inactive"), DO_LOCAL);
  782. dprintf(DP_DUMP, STR("JOIN 0\n"));
  783. }
  784. */
  785. fixmod(binname);
  786. /* replace image now */
  787. char *argv[4] = { NULL, NULL, NULL, NULL };
  788. argv[0] = strdup(binname);
  789. if (!backgrd || term_z || sdebug) {
  790. char shit[7] = "";
  791. simple_snprintf(shit, sizeof(shit), STR("-%s%s%s"), !backgrd ? "n" : "", term_z ? "t" : "", sdebug ? "D" : "");
  792. argv[1] = strdup(shit);
  793. argv[2] = strdup(conf.bot->nick);
  794. } else {
  795. argv[1] = strdup(conf.bot->nick);
  796. }
  797. unlink(conf.bot->pid_file);
  798. FILE *fp = NULL;
  799. if (!(fp = fopen(conf.bot->pid_file, "w")))
  800. return;
  801. fprintf(fp, "%d %s\n", getpid(), socks->file);
  802. fclose(fp);
  803. execvp(argv[0], &argv[0]);
  804. /* hopefully this is never reached */
  805. putlog(LOG_MISC, "*", STR("Could not restart: %s"), strerror(errno));
  806. return;
  807. }
  808. #ifdef NO
  809. void
  810. hard_restart(int idx)
  811. {
  812. write_userfile(idx);
  813. if (!conf.bot->hub) {
  814. nuke_server((char *) reason); /* let's drop the server connection ASAP */
  815. cycle_time = 0;
  816. }
  817. fatal(idx <= 0x7FF0 ? reason : NULL, 1);
  818. usleep(2000 * 500);
  819. unlink(conf.bot->pid_file); /* if this fails it is ok, cron will restart the bot, *hopefully* */
  820. simple_exec(binname, conf.bot->nick);
  821. exit(0);
  822. }
  823. #endif
  824. int updatebin(int idx, char *par, int secs)
  825. {
  826. if (!par || !par[0]) {
  827. logidx(idx, "Not enough parameters.");
  828. return 1;
  829. }
  830. size_t path_siz = strlen(binname) + strlen(par) + 2;
  831. char *path = (char *) calloc(1, path_siz);
  832. char *newbin = NULL, buf[DIRMAX] = "";
  833. const char* argv[5];
  834. int i;
  835. strlcpy(path, binname, path_siz);
  836. newbin = strrchr(path, '/');
  837. if (!newbin) {
  838. free(path);
  839. logidx(idx, STR("Don't know current binary name"));
  840. return 1;
  841. }
  842. newbin++;
  843. if (strchr(par, '/')) {
  844. *newbin = 0;
  845. logidx(idx, STR("New binary must be in %s and name must be specified without path information"), path);
  846. free(path);
  847. return 1;
  848. }
  849. strcpy(newbin, par);
  850. if (!strcmp(path, binname)) {
  851. free(path);
  852. logidx(idx, STR("Can't update with the current binary"));
  853. return 1;
  854. }
  855. if (!can_stat(path)) {
  856. logidx(idx, STR("%s can't be accessed"), path);
  857. free(path);
  858. return 1;
  859. }
  860. if (fixmod(path)) {
  861. logidx(idx, STR("Can't set mode 0600 on %s"), path);
  862. free(path);
  863. return 1;
  864. }
  865. /* Check if the new binary is compatible */
  866. int initialized_code = check_bin_initialized(path);
  867. if (initialized_code == 2) {
  868. logidx(idx, STR("New binary is corrupted or the wrong architecture/operating system."));
  869. free(path);
  870. return 1;
  871. } else if (initialized_code == 1 && !check_bin_compat(path)) {
  872. logidx(idx, STR("New binary must be initialized as pack structure has been changed in new version."));
  873. free(path);
  874. return 1;
  875. }
  876. /* make a backup just in case. */
  877. simple_snprintf(buf, sizeof(buf), STR("%s/.bin.old"), conf.datadir);
  878. copyfile(binname, buf);
  879. write_settings(path, -1, 0, initialized_code ? 0 : 1); /* re-write the binary with our packdata */
  880. Tempfile *conffile = new Tempfile("conf");
  881. if (writeconf(NULL, conffile->fd, CONF_ENC)) {
  882. logidx(idx, STR("Failed to write temporary config file for update."));
  883. delete conffile;
  884. return 1;
  885. }
  886. /* The binary should return '2' when ran with -2, if not it's probably corrupt. */
  887. putlog(LOG_DEBUG, "*", STR("Running for update binary test: %s -2"), path);
  888. argv[0] = path;
  889. argv[1] = "-2";
  890. argv[2] = 0;
  891. i = simple_exec(argv);
  892. if (i == -1 || WEXITSTATUS(i) != 2) {
  893. logidx(idx, STR("Couldn't restart new binary (error %d)"), i);
  894. delete conffile;
  895. return i;
  896. }
  897. /* now to send our config to the new binary */
  898. putlog(LOG_DEBUG, "*", STR("Running for update conf: %s -4 %s"), path, conffile->file);
  899. argv[0] = path;
  900. argv[1] = "-4";
  901. argv[2] = conffile->file;
  902. argv[3] = 0;
  903. i = simple_exec(argv);
  904. delete conffile;
  905. if (i == -1 || WEXITSTATUS(i) != 6) { /* 6 for successfull config read/write */
  906. logidx(idx, STR("Couldn't pass config to new binary (error %d)"), i);
  907. return i;
  908. }
  909. if (movefile(path, binname)) {
  910. logidx(idx, STR("Can't rename %s to %s"), path, binname);
  911. free(path);
  912. return 1;
  913. }
  914. if (updating == UPDATE_EXIT) { /* dont restart/kill/spawn bots, just die ! */
  915. printf(STR("* Moved binary to: %s\n"), binname);
  916. fatal(STR("Binary updated."), 0);
  917. }
  918. if (updating == UPDATE_AUTO) {
  919. /* Make all other bots do a soft restart */
  920. conf_checkpids(conf.bots);
  921. conf_killbot(conf.bots, NULL, NULL, SIGHUP);
  922. if (conf.bot->pid)
  923. kill(conf.bot->pid, SIGHUP);
  924. exit(0);
  925. }
  926. if (!conf.bot->hub && secs > 0) {
  927. /* Make all other bots do a soft restart */
  928. conf_checkpids(conf.bots);
  929. conf_killbot(conf.bots, NULL, NULL, SIGHUP);
  930. /* invoked with -u */
  931. if (updating == UPDATE_AUTO) {
  932. if (conf.bot->pid)
  933. kill(conf.bot->pid, SIGHUP);
  934. exit(0);
  935. }
  936. /* this odd statement makes it so specifying 1 sec will restart other bots running
  937. * and then just restart with no delay */
  938. updating = UPDATE_AUTO;
  939. if (secs > 1) {
  940. egg_timeval_t howlong;
  941. howlong.sec = secs;
  942. howlong.usec = 0;
  943. timer_create_complex(&howlong, STR("restarting for update"), (Function) restart, (void *) (long) idx, 0);
  944. } else
  945. restart(idx);
  946. return 0;
  947. } else
  948. restart(idx); /* no timer */
  949. /* this should never be reached */
  950. return 2;
  951. }
  952. int bot_aggressive_to(struct userrec *u)
  953. {
  954. if (conf.bot->localhub) {
  955. for (conf_bot* bot = conf.bots; bot && bot->nick; bot = bot->next) {
  956. if (!bot->hub && !strcmp(u->handle, bot->nick))
  957. return 1;
  958. }
  959. }
  960. char mypval[HANDLEN + 3 + 1] = "", botpval[HANDLEN + 3 + 1] = "";
  961. link_pref_val(u, botpval);
  962. link_pref_val(conf.bot->u, mypval);
  963. // sdprintf("botpval: %s", botpval);
  964. // sdprintf("mypval: %s", mypval);
  965. if (strcmp(mypval, botpval) < 0)
  966. return 1;
  967. else
  968. return 0;
  969. }
  970. int goodpass(const char *pass, int idx, char *nick)
  971. {
  972. if (!pass[0])
  973. return 0;
  974. char tell[201] = "", last = 0;
  975. int nalpha = 0, lcase = 0, ucase = 0, ocase = 0, tc, repeats = 0, score = 0;
  976. size_t length = strlen(pass);
  977. if (strchr(BADPASSCHARS, pass[0])) {
  978. simple_snprintf(tell, sizeof(tell), "Passes may not begin with '-'");
  979. goto fail;
  980. }
  981. for (int i = 0; i < (signed) length; i++) {
  982. if (pass[i] == last)
  983. repeats++;
  984. tc = (int) pass[i];
  985. if (tc < 58 && tc > 47)
  986. ocase++; /* number */
  987. else if (tc < 91 && tc > 64)
  988. ucase++; /* upper case */
  989. else if (tc < 123 && tc > 96)
  990. lcase++; /* lower case */
  991. else
  992. nalpha++; /* non-alphabet/number */
  993. last = pass[i];
  994. }
  995. score += ocase * 3;
  996. score += nalpha * 2;
  997. score += ucase * 2;
  998. score += lcase * 1;
  999. score += length * 1;
  1000. score -= repeats * 1;
  1001. simple_snprintf(tell, sizeof(tell), "Password NOT set due to being too weak. Try more characters, numbers, capitals");
  1002. if (score < 16) {
  1003. fail:
  1004. if (idx)
  1005. dprintf(idx, "%s\n", tell);
  1006. else if (nick[0])
  1007. notice(nick, tell, DP_HELP);
  1008. return 0;
  1009. }
  1010. return 1;
  1011. }
  1012. #define REPLACES 10
  1013. char *replace(const char *string, const char *oldie, const char *newbie)
  1014. {
  1015. if (string == NULL || !string[0])
  1016. return (char *) string;
  1017. if (oldie == NULL || !oldie[0])
  1018. return (char *) string;
  1019. char *c = NULL;
  1020. if ((c = (char *) strstr(string, oldie)) == NULL)
  1021. return (char *) string;
  1022. static int n = 0;
  1023. static char newstring_buf[REPLACES][1024];
  1024. char *newstring = newstring_buf[n++];
  1025. memset(newstring, 0, 1024);
  1026. if (n == REPLACES)
  1027. n = 0;
  1028. const size_t new_len = strlen(newbie), old_len = strlen(oldie), end = (strlen(string) - old_len);
  1029. size_t str_index = 0, newstr_index = 0, oldie_index = c - string, cpy_len;
  1030. while(str_index <= end && c != NULL) {
  1031. cpy_len = oldie_index-str_index;
  1032. strncpy(newstring + newstr_index, string + str_index, cpy_len);
  1033. newstr_index += cpy_len;
  1034. str_index += cpy_len;
  1035. strcpy(newstring + newstr_index, newbie);
  1036. newstr_index += new_len;
  1037. str_index += old_len;
  1038. if((c = (char *) strstr(string + str_index, oldie)) != NULL)
  1039. oldie_index = c - string;
  1040. }
  1041. strcpy(newstring + newstr_index, string + str_index);
  1042. return (newstring);
  1043. }
  1044. char* replace_vars(char *buf) {
  1045. return replace(buf, "$n", botname);
  1046. }
  1047. void showhelp(int idx, struct flag_record *flags, const char *string)
  1048. {
  1049. struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 };
  1050. size_t help_siz = strlen(string) + 1000 + 1;
  1051. char *helpstr = (char *) calloc(1, help_siz);
  1052. char tmp[2] = "", flagstr[10] = "";
  1053. bool ok = 1;
  1054. while (string && string[0]) {
  1055. if (*string == '%') {
  1056. if (!strncmp(string + 1, "{+", 2)) {
  1057. while (*string && *string != '+') {
  1058. string++;
  1059. }
  1060. flagstr[0] = 0;
  1061. while (*string && *string != '}') {
  1062. simple_snprintf(tmp, sizeof(tmp), "%c", *string);
  1063. strlcat(flagstr, tmp, sizeof(flagstr));
  1064. string++;
  1065. }
  1066. string++;
  1067. break_down_flags(flagstr, &fr, NULL);
  1068. if (flagrec_ok(&fr, flags)) {
  1069. ok = 1;
  1070. while (*string && *string != '%') {
  1071. simple_snprintf(tmp, sizeof(tmp), "%c", *string);
  1072. strlcat(helpstr, tmp, help_siz);
  1073. string++;
  1074. }
  1075. if (!strncmp(string + 1, "{-", 2)) {
  1076. ok = 1;
  1077. while (*string && *string != '}') {
  1078. string++;
  1079. }
  1080. string++;
  1081. }
  1082. } else {
  1083. ok = 0;
  1084. }
  1085. } else if (!strncmp(string + 1, "{-", 2)) {
  1086. ok = 1;
  1087. while (*string && *string != '}') {
  1088. string++;
  1089. }
  1090. string++;
  1091. } else if (*string == '{') {
  1092. while (*string && *string != '}') {
  1093. string++;
  1094. }
  1095. } else if (*(string + 1) == 'd') {
  1096. string += 2;
  1097. if (dcc[idx].u.chat->channel >= 0)
  1098. strlcat(helpstr, settings.dcc_prefix, help_siz);
  1099. } else if (*(string + 1) == '%') {
  1100. string += 2;
  1101. strlcat(helpstr, "%", help_siz);
  1102. } else {
  1103. if (ok) {
  1104. simple_snprintf(tmp, sizeof(tmp), "%c", *string);
  1105. strlcat(helpstr, tmp, help_siz);
  1106. }
  1107. string++;
  1108. }
  1109. } else {
  1110. if (ok) {
  1111. simple_snprintf(tmp, sizeof(tmp), "%c", *string);
  1112. strlcat(helpstr, tmp, help_siz);
  1113. }
  1114. string++;
  1115. }
  1116. }
  1117. helpstr[strlen(helpstr)] = 0;
  1118. if (helpstr[0]) dumplots(idx, "", helpstr);
  1119. free(helpstr);
  1120. }
  1121. /* Arrange the N elements of ARRAY in random order. */
  1122. void shuffleArray(char* array[], size_t n)
  1123. {
  1124. for (size_t i = 0; i < n; i++) {
  1125. const size_t j = randint(n);
  1126. char* temp = array[j];
  1127. array[j] = array[i];
  1128. array[i] = temp;
  1129. }
  1130. }
  1131. void shuffle(char *string, char *delim, size_t str_len)
  1132. {
  1133. char *array[501], *str = NULL, *work = NULL;
  1134. size_t len = 0;
  1135. bzero(&array, sizeof array);
  1136. work = strdup(string);
  1137. str = strtok(work, delim);
  1138. while(str && *str)
  1139. {
  1140. array[len] = str;
  1141. len++;
  1142. str = strtok((char*) NULL, delim);
  1143. }
  1144. shuffleArray(array, len);
  1145. string[0] = 0;
  1146. for (size_t i = 0; i < len; i++) {
  1147. strlcat(string, array[i], str_len);
  1148. if (i != len - 1)
  1149. strlcat(string, delim, str_len);
  1150. }
  1151. free(work);
  1152. string[strlen(string)] = 0;
  1153. }
  1154. /* returns
  1155. 1: use ANSI
  1156. 2: use mIRC
  1157. 0: neither
  1158. */
  1159. int
  1160. coloridx(int idx)
  1161. {
  1162. if (idx == -1) { /* who cares, just show color! */
  1163. return 1; /* ANSI */
  1164. } else if (idx == -2) {
  1165. return 2; /* mIRC */
  1166. /* valid idx and NOT relaying */
  1167. } else if (idx >= 0) {
  1168. if (dcc[idx].irc || dcc[idx].bot) {
  1169. return 0;
  1170. } else if ((dcc[idx].status & STAT_COLOR) && (dcc[idx].type && dcc[idx].type != &DCC_RELAYING)) {
  1171. /* telnet probably wants ANSI, even though it might be a relay from an mIRC client */
  1172. if (dcc[idx].status & STAT_TELNET || dcc[idx].sock == STDOUT)
  1173. return 1;
  1174. /* non-telnet is probably a /dcc-chat, most irc clients support mIRC codes... */
  1175. else
  1176. return 2;
  1177. }
  1178. }
  1179. return 0;
  1180. }
  1181. const char *
  1182. color(int idx, int type, int which)
  1183. {
  1184. int ansi = 0;
  1185. /* if user is connected over TELNET or !backgrd, show ANSI
  1186. * if they are relaying, they are most likely on an IRC client and should have mIRC codes
  1187. */
  1188. if ((ansi = coloridx(idx)) == 0)
  1189. return "";
  1190. if (ansi == 2)
  1191. ansi = 0;
  1192. if (type == BOLD_OPEN) {
  1193. return ansi ? "\033[1m" : "\002";
  1194. } else if (type == BOLD_CLOSE) {
  1195. // return ansi ? "\033[22m" : "\002";
  1196. return ansi ? "\033[0m" : "\002";
  1197. } else if (type == UNDERLINE_OPEN) {
  1198. return ansi ? "\033[4m" : "\037";
  1199. } else if (type == UNDERLINE_CLOSE) {
  1200. return ansi ? "\033[24m" : "\037";
  1201. } else if (type == FLASH_OPEN) {
  1202. return ansi ? "\033[5m" : "\002\037";
  1203. } else if (type == FLASH_CLOSE) {
  1204. return ansi ? "\033[0m" : "\037\002";
  1205. } else if (type == COLOR_OPEN) {
  1206. switch (which) {
  1207. case C_BLACK: return ansi ? "\033[30m" : "\00301";
  1208. case C_RED: return ansi ? "\033[31m" : "\00305";
  1209. case C_GREEN: return ansi ? "\033[32m" : "\00303";
  1210. case C_BROWN: return ansi ? "\033[33m" : "\00307";
  1211. case C_BLUE: return ansi ? "\033[34m" : "\00302";
  1212. case C_PURPLE: return ansi ? "\033[35m" : "\00306";
  1213. case C_CYAN: return ansi ? "\033[36m" : "\00310";
  1214. case C_WHITE: return ansi ? "\033[1;37m" : "\00300";
  1215. case C_DARKGREY: return ansi ? "\033[1;30m" : "\00314";
  1216. case C_LIGHTRED: return ansi ? "\033[1;31m" : "\00304";
  1217. case C_LIGHTGREEN: return ansi ? "\033[1;32m" : "\00309";
  1218. case C_LIGHTBLUE: return ansi ? "\033[1;34m" : "\00312";
  1219. case C_LIGHTPURPLE: return ansi ? "\033[1;35m" : "\00313";
  1220. case C_LIGHTCYAN: return ansi ? "\033[1;36m" : "\00311";
  1221. case C_LIGHTGREY: return ansi ? "\033[37m" : "\00315";
  1222. case C_YELLOW: return ansi ? "\033[1;33m" : "\00308";
  1223. default: break;
  1224. }
  1225. } else if (type == COLOR_CLOSE) {
  1226. return ansi ? "\033[0m" : "\00300";
  1227. }
  1228. /* This should never be reached.. */
  1229. return "";
  1230. }
  1231. char *
  1232. strtolower(char *s)
  1233. {
  1234. char *p = s;
  1235. while (*p) {
  1236. *p = tolower(*p);
  1237. p++;
  1238. }
  1239. return s;
  1240. }
  1241. char *
  1242. strtoupper(char *s)
  1243. {
  1244. char *p = s;
  1245. while (*p) {
  1246. *p = toupper(*p);
  1247. p++;
  1248. }
  1249. return s;
  1250. }
  1251. char *step_thru_file(FILE *fd)
  1252. {
  1253. if (fd == NULL) {
  1254. return NULL;
  1255. }
  1256. char tempBuf[1024] = "", *retStr = NULL;
  1257. size_t ret_siz = 0;
  1258. while (!feof(fd)) {
  1259. if (fgets(tempBuf, sizeof(tempBuf), fd) && !feof(fd)) {
  1260. if (retStr == NULL) {
  1261. ret_siz = strlen(tempBuf) + 2;
  1262. retStr = (char *) calloc(1, ret_siz);
  1263. strlcpy(retStr, tempBuf, ret_siz);
  1264. } else {
  1265. ret_siz = strlen(retStr) + strlen(tempBuf);
  1266. retStr = (char *) realloc(retStr, ret_siz);
  1267. strlcat(retStr, tempBuf, ret_siz);
  1268. }
  1269. if (retStr[strlen(retStr)-1] == '\n') {
  1270. retStr[strlen(retStr)-1] = 0;
  1271. break;
  1272. }
  1273. }
  1274. }
  1275. return retStr;
  1276. }
  1277. char *trim(char *string)
  1278. {
  1279. if (string) {
  1280. char *ibuf = NULL, *obuf = NULL;
  1281. for (ibuf = obuf = string; *ibuf; ) {
  1282. while (*ibuf && (isspace (*ibuf)))
  1283. ibuf++;
  1284. if (*ibuf && (obuf != string))
  1285. *(obuf++) = ' ';
  1286. while (*ibuf && (!isspace (*ibuf)))
  1287. *(obuf++) = *(ibuf++);
  1288. }
  1289. *obuf = '\0';
  1290. }
  1291. return (string);
  1292. }
  1293. int skipline (char *line, int *skip) {
  1294. static int multi = 0;
  1295. if (strstr(line, "*/"))
  1296. multi = 0;
  1297. if ( (!strncmp(line, "#", 1)) || (!strncmp(line, ";", 1)) || (!strncmp(line, "//", 2)) ) {
  1298. (*skip)++;
  1299. } else if ( (strstr(line, "/*")) && (strstr(line, "*/")) ) {
  1300. multi = 0;
  1301. (*skip)++;
  1302. } else if ( (strstr(line, "/*")) ) {
  1303. (*skip)++;
  1304. multi = 1;
  1305. } else if ( (strstr(line, "*/")) ) {
  1306. multi = 0;
  1307. } else {
  1308. if (!multi) (*skip) = 0;
  1309. }
  1310. return (*skip);
  1311. }
  1312. /* vim: set sts=2 sw=2 ts=8 et: */