PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/function.c

https://github.com/rakaur/shrike
C | 854 lines | 616 code | 172 blank | 66 comment | 186 complexity | 12df576ecd967004db0399542f44c0cf MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Copyright (c) 2003-2011 Eric Will <rakaur@malkier.net>
  3. * Rights to this code are documented in doc/LICENSE.
  4. *
  5. * This file contains misc routines.
  6. */
  7. #include "../inc/shrike.h"
  8. FILE *log_file;
  9. #if !HAVE_STRLCAT
  10. /* i hate linux. */
  11. size_t strlcat(char *dst, const char *src, size_t siz)
  12. {
  13. char *d = dst;
  14. const char *s = src;
  15. size_t n = siz;
  16. size_t dlen;
  17. /* find the end of dst and adjust bytes left but don't go past end */
  18. while (n-- != 0 && *d != '\0')
  19. d++;
  20. dlen = d - dst;
  21. n = siz - dlen;
  22. if (n == 0)
  23. return (dlen + strlen(s));
  24. while (*s != '\0')
  25. {
  26. if (n != 1)
  27. {
  28. *d++ = *s;
  29. n--;
  30. }
  31. s++;
  32. }
  33. *d = '\0';
  34. return (dlen + (s - src)); /* count does not include NUL */
  35. }
  36. #endif
  37. #if !HAVE_STRLCPY
  38. /* i hate linux. */
  39. size_t strlcpy(char *dst, const char *src, size_t siz)
  40. {
  41. char *d = dst;
  42. const char *s = src;
  43. size_t n = siz;
  44. if (n != 0 && --n != 0)
  45. {
  46. do
  47. {
  48. if (!(*d++ = *s++))
  49. break;
  50. } while (--n != 0);
  51. }
  52. if (!n)
  53. {
  54. if (siz != 0)
  55. *d = '\0';
  56. while (*s++);
  57. }
  58. return (s - src - 1);
  59. }
  60. #endif
  61. #if HAVE_GETTIMEOFDAY
  62. /* starts a timer */
  63. void s_time(struct timeval *sttime)
  64. {
  65. gettimeofday(sttime, NULL);
  66. }
  67. #endif
  68. #if HAVE_GETTIMEOFDAY
  69. /* ends a timer */
  70. void e_time(struct timeval sttime, struct timeval *ttime)
  71. {
  72. struct timeval now;
  73. gettimeofday(&now, NULL);
  74. timersub(&now, &sttime, ttime);
  75. }
  76. #endif
  77. #if HAVE_GETTIMEOFDAY
  78. /* translates microseconds into miliseconds */
  79. int32_t tv2ms(struct timeval *tv)
  80. {
  81. return (tv->tv_sec * 1000) + (int32_t) (tv->tv_usec / 1000);
  82. }
  83. #endif
  84. /* replaces tabs with a single ASCII 32 */
  85. void tb2sp(char *line)
  86. {
  87. char *c;
  88. while ((c = strchr(line, '\t')))
  89. *c = ' ';
  90. }
  91. /* copy at most len-1 characters from a string to a buffer, NULL terminate */
  92. char *strscpy(char *d, const char *s, size_t len)
  93. {
  94. char *d_orig = d;
  95. if (!len)
  96. return d;
  97. while (--len && (*d++ = *s++));
  98. *d = 0;
  99. return d_orig;
  100. }
  101. /* does malloc()'s job and dies if malloc() fails */
  102. void *smalloc(size_t size)
  103. {
  104. void *buf = malloc(size);
  105. if (!buf)
  106. raise(SIGUSR1);
  107. return buf;
  108. }
  109. /* does calloc()'s job and dies if calloc() fails */
  110. void *scalloc(size_t elsize, size_t els)
  111. {
  112. void *buf = calloc(elsize, els);
  113. if (!buf)
  114. raise(SIGUSR1);
  115. return buf;
  116. }
  117. /* does realloc()'s job and dies if realloc() fails */
  118. void *srealloc(void *oldptr, size_t newsize)
  119. {
  120. void *buf = realloc(oldptr, newsize);
  121. if (!buf)
  122. raise(SIGUSR1);
  123. return buf;
  124. }
  125. /* does strdup()'s job, only with the above memory functions */
  126. char *sstrdup(const char *s)
  127. {
  128. char *t = smalloc(strlen(s) + 1);
  129. strcpy(t, s);
  130. return t;
  131. }
  132. /* removes unwanted chars from a line */
  133. void strip(char *line)
  134. {
  135. char *c;
  136. if (line)
  137. {
  138. if ((c = strchr(line, '\n')))
  139. *c = '\0';
  140. if ((c = strchr(line, '\r')))
  141. *c = '\0';
  142. if ((c = strchr(line, '\1')))
  143. *c = '\0';
  144. }
  145. }
  146. /* logs something to shrike.log */
  147. void slog(uint32_t level, const char *fmt, ...)
  148. {
  149. time_t t;
  150. struct tm tm;
  151. va_list args;
  152. char timebuf[64];
  153. char buf[BUFSIZE];
  154. if (!level || fmt == NULL)
  155. return;
  156. if (level > me.loglevel)
  157. return;
  158. va_start(args, fmt);
  159. vsnprintf(buf, BUFSIZE, fmt, args);
  160. va_end(args);
  161. time(&t);
  162. tm = *localtime(&t);
  163. strftime(timebuf, sizeof(timebuf) - 1, "[%d/%m %H:%M:%S] ", &tm);
  164. if (!log_file)
  165. {
  166. FILE *f = fopen("var/shrike.log", "a");
  167. if (f == NULL)
  168. exit(EXIT_FAILURE);
  169. log_file = f;
  170. }
  171. fprintf(log_file, "%s %s\n", timebuf, buf);
  172. fflush(log_file);
  173. if ((runflags & (RF_LIVE | RF_STARTING)))
  174. printf("%s %s\n", timebuf, buf);
  175. }
  176. /* return the current time in milliseconds */
  177. uint32_t time_msec(void)
  178. {
  179. #ifdef HAVE_GETTIMEOFDAY
  180. struct timeval tv;
  181. gettimeofday(&tv, NULL);
  182. return tv.tv_sec * 1000 + tv.tv_usec / 1000;
  183. #else
  184. return CURRTIME * 1000;
  185. #endif
  186. }
  187. /* performs a regex match */
  188. uint8_t regex_match(regex_t * preg, char *pattern, char *string,
  189. size_t nmatch, regmatch_t pmatch[], int eflags)
  190. {
  191. static char errmsg[256];
  192. int errnum;
  193. /* compile regex */
  194. preg = (regex_t *) smalloc(sizeof(*preg));
  195. errnum = regcomp(preg, pattern, REG_ICASE | REG_EXTENDED);
  196. if (errnum != 0)
  197. {
  198. regerror(errnum, preg, errmsg, 256);
  199. slog(LG_ERROR, "regex_match(): %s\n", errmsg);
  200. free(preg);
  201. preg = NULL;
  202. return 1;
  203. }
  204. /* match it */
  205. if (regexec(preg, string, 5, pmatch, 0) != 0)
  206. return 1;
  207. return 0;
  208. }
  209. /* generates a hash value
  210. *
  211. * this is based on one_at_a_time() and is used in Perl
  212. * 2006 Bob Jenkins <bob_jenkins@burtleburtle.net>
  213. */
  214. uint32_t shash(const char *text)
  215. {
  216. uint32_t hash = 0;
  217. char c;
  218. while ((c = ToLower(*text++)))
  219. {
  220. hash += c;
  221. hash += (hash << 10);
  222. hash ^= (hash >> 6);
  223. }
  224. hash += (hash << 3);
  225. hash ^= (hash >> 11);
  226. hash += (hash << 15);
  227. #ifdef LARGE_NETWORK
  228. return (hash & hashmask(15));
  229. #else
  230. return (hash & hashmask(11));
  231. #endif
  232. }
  233. /* replace all occurances of 'old' with 'new' */
  234. char *replace(char *s, int32_t size, const char *old, const char *new)
  235. {
  236. char *ptr = s;
  237. int32_t left = strlen(s);
  238. int32_t avail = size - (left + 1);
  239. int32_t oldlen = strlen(old);
  240. int32_t newlen = strlen(new);
  241. int32_t diff = newlen - oldlen;
  242. while (left >= oldlen)
  243. {
  244. if (strncmp(ptr, old, oldlen))
  245. {
  246. left--;
  247. ptr++;
  248. continue;
  249. }
  250. if (diff > avail)
  251. break;
  252. if (diff != 0)
  253. memmove(ptr + oldlen + diff, ptr + oldlen, left + 1);
  254. strncpy(ptr, new, newlen);
  255. ptr += newlen;
  256. left -= oldlen;
  257. }
  258. return s;
  259. }
  260. /* reverse of atoi() */
  261. char *itoa(int num)
  262. {
  263. static char ret[32];
  264. snprintf(ret, 32, "%d", num);
  265. return ret;
  266. }
  267. /* channel modes we support */
  268. struct flag
  269. {
  270. char mode;
  271. int32_t flag;
  272. char prefix;
  273. };
  274. static const struct flag cmodes[] = {
  275. {'t', CMODE_TOPIC, 0},
  276. {'n', CMODE_NOEXT, 0},
  277. {'s', CMODE_SEC, 0},
  278. {'m', CMODE_MOD, 0},
  279. {'l', CMODE_LIMIT, 0},
  280. {'i', CMODE_INVITE, 0},
  281. {'p', CMODE_PRIV, 0},
  282. {'k', CMODE_KEY, 0},
  283. {0, 0}
  284. };
  285. static const struct flag cumodes[] = {
  286. {'o', CMODE_OP, '@'},
  287. {'v', CMODE_VOICE, '+'},
  288. {0, 0, 0}
  289. };
  290. /* convert mode flags to a text mode string */
  291. char *flags_to_string(int32_t flags)
  292. {
  293. static char buf[32];
  294. char *s = buf;
  295. int i;
  296. for (i = 0; cmodes[i].mode != 0; i++)
  297. if (flags & cmodes[i].flag)
  298. *s++ = cmodes[i].mode;
  299. *s = 0;
  300. return buf;
  301. }
  302. /* convert a mode character to a flag. */
  303. int32_t mode_to_flag(char c)
  304. {
  305. int i;
  306. for (i = 0; cmodes[i].mode != 0 && cmodes[i].mode != c; i++);
  307. return cmodes[i].flag;
  308. }
  309. /* return the time elapsed since an event */
  310. char *time_ago(time_t event)
  311. {
  312. static char ret[128];
  313. int years, weeks, days, hours, minutes, seconds;
  314. event = CURRTIME - event;
  315. years = weeks = days = hours = minutes = 0;
  316. while (event >= 60 * 60 * 24 * 365)
  317. {
  318. event -= 60 * 60 * 24 * 365;
  319. years++;
  320. }
  321. while (event >= 60 * 60 * 24 * 7)
  322. {
  323. event -= 60 * 60 * 24 * 7;
  324. weeks++;
  325. }
  326. while (event >= 60 * 60 * 24)
  327. {
  328. event -= 60 * 60 * 24;
  329. days++;
  330. }
  331. while (event >= 60 * 60)
  332. {
  333. event -= 60 * 60;
  334. hours++;
  335. }
  336. while (event >= 60)
  337. {
  338. event -= 60;
  339. minutes++;
  340. }
  341. seconds = event;
  342. if (years)
  343. snprintf(ret, sizeof(ret),
  344. "%d year%s, %d week%s, %d day%s, %02d:%02d:%02d",
  345. years, years == 1 ? "" : "s",
  346. weeks, weeks == 1 ? "" : "s",
  347. days, days == 1 ? "" : "s", hours, minutes, seconds);
  348. else if (weeks)
  349. snprintf(ret, sizeof(ret), "%d week%s, %d day%s, %02d:%02d:%02d",
  350. weeks, weeks == 1 ? "" : "s",
  351. days, days == 1 ? "" : "s", hours, minutes, seconds);
  352. else if (days)
  353. snprintf(ret, sizeof(ret), "%d day%s, %02d:%02d:%02d",
  354. days, days == 1 ? "" : "s", hours, minutes, seconds);
  355. else if (hours)
  356. snprintf(ret, sizeof(ret), "%d hour%s, %d minute%s, %d second%s",
  357. hours, hours == 1 ? "" : "s",
  358. minutes, minutes == 1 ? "" : "s",
  359. seconds, seconds == 1 ? "" : "s");
  360. else if (minutes)
  361. snprintf(ret, sizeof(ret), "%d minute%s, %d second%s",
  362. minutes, minutes == 1 ? "" : "s",
  363. seconds, seconds == 1 ? "" : "s");
  364. else
  365. snprintf(ret, sizeof(ret), "%d second%s",
  366. seconds, seconds == 1 ? "" : "s");
  367. return ret;
  368. }
  369. char *timediff(time_t seconds)
  370. {
  371. static char buf[BUFSIZE];
  372. int days, hours, minutes;
  373. days = (int)(seconds / 86400);
  374. seconds %= 86400;
  375. hours = (int)(seconds / 3600);
  376. hours %= 3600;
  377. minutes = (int)(seconds / 60);
  378. minutes %= 60;
  379. seconds %= 60;
  380. snprintf(buf, sizeof(buf), "%d day%s, %d:%02d:%02lu",
  381. days, (days == 1) ? "" : "s", hours,
  382. minutes, (unsigned long)seconds);
  383. return buf;
  384. }
  385. /* generate a random number, for use as a key */
  386. unsigned long makekey(void)
  387. {
  388. unsigned long i, j, k;
  389. i = rand() % (CURRTIME / cnt.user + 1);
  390. j = rand() % (me.start * cnt.chan + 1);
  391. if (i > j)
  392. k = (i - j) + strlen(svs.user);
  393. else
  394. k = (j - i) + strlen(svs.host);
  395. /* shorten or pad it to 9 digits */
  396. if (k > 1000000000)
  397. k = k - 1000000000;
  398. if (k < 100000000)
  399. k = k + 100000000;
  400. return k;
  401. }
  402. int validemail(char *email)
  403. {
  404. int i, valid = 1, chars = 0;
  405. /* if it starts with a dash it'll mess up the MTA
  406. * i have no idea if emails are otherwise allowed to
  407. * start with dashes, but if they are they'd better not
  408. * use one to register with shrike :(
  409. */
  410. if (*email == '-')
  411. valid = 0;
  412. /* make sure it has @ and . */
  413. if (!strchr(email, '@') || !strchr(email, '.'))
  414. valid = 0;
  415. /* check for other bad things */
  416. if (strchr(email, '$') || strchr(email, '/') ||
  417. strchr(email, ';') || strchr(email, '<') ||
  418. strchr(email, '>') || strchr(email, '&'))
  419. valid = 0;
  420. /* make sure there are at least 6 characters besides the above
  421. * mentioned @ and .
  422. */
  423. for (i = strlen(email) - 1; i > 0; i--)
  424. if (!(email[i] == '@' || email[i] == '.'))
  425. chars++;
  426. if (chars < 6)
  427. valid = 0;
  428. return valid;
  429. }
  430. boolean_t validhostmask(char *host)
  431. {
  432. /* make sure it has ! and @ */
  433. if (!strchr(host, '!') || !strchr(host, '@'))
  434. return FALSE;
  435. return TRUE;
  436. }
  437. /* send the specified type of email.
  438. *
  439. * what is what we're sending to, a username.
  440. *
  441. * param is an extra parameter; email, key, etc.
  442. *
  443. * If type ==:
  444. * 1 - username REGISTER
  445. * 2 - username SENDPASS
  446. * 3 - username SET:EMAIL
  447. * 4 - channel SENDPASS
  448. */
  449. void sendemail(char *what, const char *param, int type)
  450. {
  451. myuser_t *mu;
  452. mychan_t *mc;
  453. char *email, *date, *pass = NULL;
  454. char cmdbuf[512], timebuf[256], to[128], from[128], subject[128];
  455. FILE *out;
  456. time_t t;
  457. struct tm tm;
  458. if (type == 1 || type == 2 || type == 3)
  459. {
  460. if (!(mu = myuser_find(what)))
  461. return;
  462. if (type == 1 || type == 3)
  463. pass = itoa(mu->key);
  464. else
  465. pass = mu->pass;
  466. if (type == 3)
  467. email = mu->temp;
  468. else
  469. email = mu->email;
  470. }
  471. else
  472. {
  473. if (!(mc = mychan_find(what)))
  474. return;
  475. mu = mc->founder;
  476. pass = mc->pass;
  477. email = mu->email;
  478. }
  479. /* set up the email headers */
  480. time(&t);
  481. tm = *gmtime(&t);
  482. strftime(timebuf, sizeof(timebuf) - 1, "%a, %d %b %Y %H:%M:%S %z", &tm);
  483. date = timebuf;
  484. snprintf(from, 128, "%s <%s@%s>", svs.nick, svs.user, svs.host);
  485. snprintf(to, 128, "%s <%s>", mu->name, email);
  486. if (type == 1)
  487. strlcpy(subject, "Username Registration", 128);
  488. else if (type == 2 || type == 4)
  489. strlcpy(subject, "Password Retrieval", 128);
  490. else if (type == 3)
  491. strlcpy(subject, "Change Email Confirmation", 128);
  492. /* now set up the email */
  493. snprintf(cmdbuf, 512, "%s %s", me.mta, email);
  494. out = popen(cmdbuf, "w");
  495. fprintf(out, "From: %s\n", from);
  496. fprintf(out, "To: %s\n", to);
  497. fprintf(out, "Subject: %s\n", subject);
  498. fprintf(out, "Date: %s\n\n", date);
  499. fprintf(out, "%s,\n\n", mu->name);
  500. fprintf(out, "Thank you for your interest in the %s IRC network.\n\n",
  501. me.netname);
  502. if (type == 1)
  503. {
  504. fprintf(out, "In order to complete your registration, you must send "
  505. "the following command on IRC:\n");
  506. fprintf(out, "/MSG %s REGISTER %s KEY %s\n\n", svs.nick, what, pass);
  507. fprintf(out, "Thank you for registering your username on the %s IRC "
  508. "network!\n", me.netname);
  509. }
  510. else if (type == 2 || type == 4)
  511. {
  512. fprintf(out, "Someone has requested the password for %s be sent to the "
  513. "corresponding email address. If you did not request this action "
  514. "please let us know.\n\n", what);
  515. fprintf(out, "The password for %s is %s. Please write this down for "
  516. "future reference.\n", what, pass);
  517. }
  518. else if (type == 3)
  519. {
  520. fprintf(out, "In order to complete your email change, you must send "
  521. "the following command on IRC:\n");
  522. fprintf(out, "/MSG %s SET %s EMAIL %s\n\n", svs.nick, what, pass);
  523. }
  524. fprintf(out, ".\n");
  525. pclose(out);
  526. }
  527. /* various access level checkers */
  528. boolean_t is_founder(mychan_t *mychan, myuser_t *myuser)
  529. {
  530. if (!myuser)
  531. return FALSE;
  532. if (mychan->founder == myuser)
  533. return TRUE;
  534. if ((chanacs_find(mychan, myuser, CA_FOUNDER)))
  535. return TRUE;
  536. return FALSE;
  537. }
  538. boolean_t is_successor(mychan_t *mychan, myuser_t *myuser)
  539. {
  540. if (!myuser)
  541. return FALSE;
  542. if (mychan->successor == myuser)
  543. return TRUE;
  544. if ((chanacs_find(mychan, myuser, CA_SUCCESSOR)))
  545. return TRUE;
  546. return FALSE;
  547. }
  548. boolean_t is_xop(mychan_t *mychan, myuser_t *myuser, uint8_t level)
  549. {
  550. if (!myuser)
  551. return FALSE;
  552. if (chanacs_find(mychan, myuser, level))
  553. return TRUE;
  554. return FALSE;
  555. }
  556. boolean_t is_xop_host(mychan_t *mychan, user_t *user, uint8_t level)
  557. {
  558. char hostbuf[BUFSIZE];
  559. snprintf(hostbuf, BUFSIZE, "%s!%s@%s", user->nick, user->user, user->host);
  560. if (chanacs_find_host(mychan, hostbuf, level))
  561. return TRUE;
  562. return FALSE;
  563. }
  564. boolean_t should_op(mychan_t *mychan, user_t *user)
  565. {
  566. chanuser_t *cu;
  567. myuser_t *mu = user->myuser;
  568. if (!mu)
  569. return FALSE;
  570. if (MC_NEVEROP & mychan->flags)
  571. return FALSE;
  572. if (MU_NEVEROP & mu->flags)
  573. return FALSE;
  574. cu = chanuser_find(mychan->chan, user);
  575. if (!cu)
  576. return FALSE;
  577. if (CMODE_OP & cu->modes)
  578. return FALSE;
  579. if ((is_founder(mychan, mu)) || (is_successor(mychan, mu)))
  580. return TRUE;
  581. if (is_xop(mychan, mu, (CA_SOP | CA_AOP)))
  582. return TRUE;
  583. return FALSE;
  584. }
  585. boolean_t should_op_host(mychan_t *mychan, char *host)
  586. {
  587. char hostbuf[BUFSIZE];
  588. snprintf(hostbuf, BUFSIZE, "%s!%s@%s", svs.nick, svs.user, svs.host);
  589. if (!match(host, hostbuf))
  590. return FALSE;
  591. if (chanacs_find_host(mychan, host, CA_AOP))
  592. return TRUE;
  593. return FALSE;
  594. }
  595. boolean_t should_voice(mychan_t *mychan, user_t *user)
  596. {
  597. chanuser_t *cu;
  598. myuser_t *mu = user->myuser;
  599. if (!mu)
  600. return FALSE;
  601. if (MC_NEVEROP & mychan->flags)
  602. return FALSE;
  603. if (MU_NEVEROP & mu->flags)
  604. return FALSE;
  605. cu = chanuser_find(mychan->chan, user);
  606. if (!cu)
  607. return FALSE;
  608. if (CMODE_VOICE & cu->modes)
  609. return FALSE;
  610. if (is_xop(mychan, mu, CA_VOP))
  611. return TRUE;
  612. return FALSE;
  613. }
  614. boolean_t should_voice_host(mychan_t *mychan, char *host)
  615. {
  616. char hostbuf[BUFSIZE];
  617. snprintf(hostbuf, BUFSIZE, "%s!%s@%s", svs.nick, svs.user, svs.host);
  618. if (!match(host, hostbuf))
  619. return FALSE;
  620. if (chanacs_find_host(mychan, host, CA_VOP))
  621. return TRUE;
  622. return FALSE;
  623. }
  624. boolean_t is_sra(myuser_t *myuser)
  625. {
  626. if (!myuser)
  627. return FALSE;
  628. if (myuser->sra)
  629. return TRUE;
  630. return FALSE;
  631. }
  632. boolean_t is_ircop(user_t *user)
  633. {
  634. if (UF_IRCOP & user->flags)
  635. return TRUE;
  636. return FALSE;
  637. }
  638. boolean_t is_admin(user_t *user)
  639. {
  640. if (UF_ADMIN & user->flags)
  641. return TRUE;
  642. return FALSE;
  643. }
  644. /* stolen from Sentinel */
  645. int token_to_value(struct Token token_table[], char *token)
  646. {
  647. int i;
  648. if ((token_table != NULL) && (token != NULL))
  649. {
  650. for (i = 0; token_table[i].text != NULL; i++)
  651. {
  652. if (strcasecmp(token_table[i].text, token) == 0)
  653. {
  654. return token_table[i].value;
  655. }
  656. }
  657. /* If no match... */
  658. return TOKEN_UNMATCHED;
  659. }
  660. /* Otherwise... */
  661. return TOKEN_ERROR;
  662. }
  663. char *sbytes(float x)
  664. {
  665. if (x > 1073741824.0)
  666. return "GB";
  667. else if (x > 1048576.0)
  668. return "MB";
  669. else if (x > 1024.0)
  670. return "KB";
  671. return "B";
  672. }
  673. float bytes(float x)
  674. {
  675. if (x > 1073741824.0)
  676. return (x / 1073741824.0);
  677. if (x > 1048576.0)
  678. return (x / 1048576.0);
  679. if (x > 1024.0)
  680. return (x / 1024.0);
  681. return x;
  682. }