PageRenderTime 27ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/function.c

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