ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/function.C
Revision: 1.7
Committed: Sun Sep 9 20:05:52 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.6: +3 -10 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

File Contents

# Content
1 /*
2 * function.C: Miscellaneous functions.
3 * Rights to this code are documented in doc/pod/license.pod.
4 *
5 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team (http://ermyth.schmorp.de)
6 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
7 */
8
9 static char const rcsid[] = "$Id: function.C,v 1.6 2007-09-05 11:23:15 pippijn Exp $";
10
11 #include "atheme.h"
12 #include <common/util.h>
13 #include <ermyth/crypto.h>
14 #include <account/mychan.h>
15 #include <account/chanacs.h>
16 #include <account/myuser.h>
17 #include <common/random.h>
18
19 char ch[27] = "abcdefghijklmnopqrstuvwxyz";
20
21 /* This function uses allocates memory.
22 * You MUST free the result when you are done with it!
23 */
24 char *
25 gen_pw (int sz)
26 {
27 int i;
28 char *buf = salloc<char> (sz + 1); /* padding */
29
30 for (i = 0; i < sz; i++)
31 {
32 buf[i] = ch[gen_rand32 () % 26];
33 }
34
35 buf[sz] = 0;
36
37 return buf;
38 }
39
40 #ifdef HAVE_GETTIMEOFDAY
41 /* starts a timer */
42 void
43 s_time (struct timeval *sttime)
44 {
45 gettimeofday (sttime, NULL);
46 }
47 #endif
48
49 #ifdef HAVE_GETTIMEOFDAY
50 /* ends a timer */
51 void
52 e_time (struct timeval sttime, struct timeval *ttime)
53 {
54 struct timeval now;
55
56 gettimeofday (&now, NULL);
57 timersub (&now, &sttime, ttime);
58 }
59 #endif
60
61 #ifdef HAVE_GETTIMEOFDAY
62 /* translates microseconds into miliseconds */
63 int
64 tv2ms (struct timeval *tv)
65 {
66 return (tv->tv_sec * 1000) + (int) (tv->tv_usec / 1000);
67 }
68 #endif
69
70 /* replaces tabs with a single ASCII 32 */
71 void
72 tb2sp (char *line)
73 {
74 char *c;
75
76 while ((c = strchr (line, '\t')))
77 *c = ' ';
78 }
79
80 /* replace all occurances of 'oldstr' with 'newstr' */
81 char *
82 replace (char *s, int size, char const * const oldstr, char const * const newstr)
83 {
84 char *ptr = s;
85 int left = strlen (s);
86 int avail = size - (left + 1);
87 int oldstrlen = strlen (oldstr);
88 int newstrlen = strlen (newstr);
89 int diff = newstrlen - oldstrlen;
90
91 while (left >= oldstrlen)
92 {
93 if (strncmp (ptr, oldstr, oldstrlen))
94 {
95 left--;
96 ptr++;
97 continue;
98 }
99
100 if (diff > avail)
101 break;
102
103 if (diff != 0)
104 memmove (ptr + oldstrlen + diff, ptr + oldstrlen, left + 1);
105
106 memcpy (ptr, newstr, newstrlen);
107 ptr += newstrlen;
108 left -= oldstrlen;
109 }
110
111 return s;
112 }
113
114 /* return the time elapsed since an event */
115 char *
116 time_ago (time_t event)
117 {
118 static char ret[128];
119 int years, weeks, days, hours, minutes, seconds;
120
121 event = NOW - event;
122 years = weeks = days = hours = minutes = seconds = 0;
123
124 while (event >= 60 * 60 * 24 * 365)
125 {
126 event -= 60 * 60 * 24 * 365;
127 years++;
128 }
129 while (event >= 60 * 60 * 24 * 7)
130 {
131 event -= 60 * 60 * 24 * 7;
132 weeks++;
133 }
134 while (event >= 60 * 60 * 24)
135 {
136 event -= 60 * 60 * 24;
137 days++;
138 }
139 while (event >= 60 * 60)
140 {
141 event -= 60 * 60;
142 hours++;
143 }
144 while (event >= 60)
145 {
146 event -= 60;
147 minutes++;
148 }
149
150 seconds = event;
151
152 if (years)
153 snprintf (ret, sizeof (ret), "%d year%s, %d week%s, %d day%s, %02d:%02d:%02d", years, years == 1 ? "" : "s", weeks, weeks == 1 ? "" : "s", days, days == 1 ? "" : "s", hours, minutes, seconds);
154 else if (weeks)
155 snprintf (ret, sizeof (ret), "%d week%s, %d day%s, %02d:%02d:%02d", weeks, weeks == 1 ? "" : "s", days, days == 1 ? "" : "s", hours, minutes, seconds);
156 else if (days)
157 snprintf (ret, sizeof (ret), "%d day%s, %02d:%02d:%02d", days, days == 1 ? "" : "s", hours, minutes, seconds);
158 else if (hours)
159 snprintf (ret, sizeof (ret), "%d hour%s, %d minute%s, %d second%s", hours, hours == 1 ? "" : "s", minutes, minutes == 1 ? "" : "s", seconds, seconds == 1 ? "" : "s");
160 else if (minutes)
161 snprintf (ret, sizeof (ret), "%d minute%s, %d second%s", minutes, minutes == 1 ? "" : "s", seconds, seconds == 1 ? "" : "s");
162 else
163 snprintf (ret, sizeof (ret), "%d second%s", seconds, seconds == 1 ? "" : "s");
164
165 return ret;
166 }
167
168 char *
169 timediff (time_t seconds)
170 {
171 static char buf[BUFSIZE];
172 long unsigned days, hours, minutes;
173
174 days = seconds / 86400;
175 seconds %= 86400;
176 hours = seconds / 3600;
177 hours %= 3600;
178 minutes = seconds / 60;
179 minutes %= 60;
180 seconds %= 60;
181
182 snprintf (buf, sizeof (buf), "%lu day%s, %lu:%02lu:%02lu", days, (days == 1) ? "" : "s", hours, minutes, (long unsigned) seconds);
183
184 return buf;
185 }
186
187 /* generate a random number, for use as a key */
188 unsigned long
189 makekey (void)
190 {
191 unsigned long k;
192
193 k = gen_rand32 () & 0x7FFFFFFF;
194
195 /* shorten or pad it to 9 digits */
196 if (k > 1000000000)
197 k = k - 1000000000;
198 if (k < 100000000)
199 k = k + 100000000;
200
201 return k;
202 }
203
204 bool
205 is_internal_client (user_t *u)
206 {
207 return (u && (!u->server || u->server == me.me));
208 }
209
210 int
211 validemail (char *email)
212 {
213 int i, valid = 1, chars = 0;
214
215 /* sane length */
216 if (strlen (email) >= EMAILLEN)
217 valid = 0;
218
219 /* make sure it has @ and . */
220 if (!strchr (email, '@') || !strchr (email, '.'))
221 valid = 0;
222
223 /* check for other bad things */
224 if (strchr (email, '\'') || strchr (email, ' ') || strchr (email, ',') || strchr (email, '$') || strchr (email, '/') || strchr (email, ';') || strchr (email, '<') || strchr (email, '>') || strchr (email, '&') || strchr (email, '"'))
225 valid = 0;
226
227 /* make sure there are at least 6 characters besides the above
228 * mentioned @ and .
229 */
230 for (i = strlen (email) - 1; i > 0; i--)
231 if (!(email[i] == '@' || email[i] == '.'))
232 chars++;
233
234 if (chars < 6)
235 valid = 0;
236
237 return valid;
238 }
239
240 bool
241 validhostmask (char *host)
242 {
243 char *p, *q;
244
245 if (strchr (host, ' '))
246 return false;
247
248 /* make sure it has ! and @ in that order and only once */
249 p = strchr (host, '!');
250 q = strchr (host, '@');
251 if (p == NULL || q == NULL || p > q || strchr (p + 1, '!') || strchr (q + 1, '@'))
252 return false;
253
254 /* XXX this NICKLEN is too long */
255 if (strlen (host) > NICKLEN + USERLEN + HOSTLEN + 1)
256 return false;
257
258 if (host[0] == ',' || host[0] == '-' || host[0] == '#' || host[0] == '@' || host[0] == '!')
259 return false;
260
261 return true;
262 }
263
264 /* send the specified type of email.
265 *
266 * u is whoever caused this to be called, the corresponding service
267 * in case of xmlrpc
268 * type is EMAIL_*, see include/tools.h
269 * mu is the recipient user
270 * param depends on type, also see include/tools.h
271 */
272 int
273 sendemail (user_t *u, int type, myuser_t *mu, char const * const param)
274 {
275 char *email, *date = NULL;
276 char cmdbuf[512], timebuf[256], to[128], from[128], subject[128];
277 FILE *out;
278 time_t t;
279 struct tm tm;
280 int pipfds[2];
281 pid_t pid;
282 int status;
283 int rc;
284 static time_t period_start = 0, lastwallops = 0;
285 static unsigned emailcount = 0;
286
287 if (u == NULL || mu == NULL)
288 return 0;
289
290 if (me.mta == NULL)
291 {
292 if (type != EMAIL_MEMO && !is_internal_client (u))
293 notice (opersvs.me ? opersvs.nick : me.name, u->nick, "Sending email is administratively disabled.");
294 return 0;
295 }
296
297 if (type == EMAIL_SETEMAIL)
298 {
299 /* special case for e-mail change */
300 metadata *md = mu->find_metadata ("private:verify:emailchg:newemail");
301
302 if (md && md->value)
303 email = md->value;
304 else /* should NEVER happen */
305 {
306 slog (LG_ERROR, "sendemail(): got email change request, but newemail unset!");
307 return 0;
308 }
309 }
310 else
311 email = mu->email;
312
313 if (NOW - period_start > me.emailtime)
314 {
315 emailcount = 0;
316 period_start = NOW;
317 }
318 emailcount++;
319 if (emailcount > me.emaillimit)
320 {
321 if (NOW - lastwallops > 60)
322 {
323 wallops (_("Rejecting email for %s[%s@%s] due to too high load (type %d to %s <%s>)"), u->nick, u->user, u->vhost, type, mu->name, email);
324 slog (LG_ERROR, "sendemail(): rejecting email for %s[%s@%s] (%s) due to too high load (type %d to %s <%s>)", u->nick, u->user, u->vhost, u->ip[0] ? u->ip : u->host, type, mu->name, email);
325 lastwallops = NOW;
326 }
327 return 0;
328 }
329
330 slog (LG_INFO, "sendemail(): email for %s[%s@%s] (%s) type %d to %s <%s>", u->nick, u->user, u->vhost, u->ip[0] ? u->ip : u->host, type, mu->name, email);
331
332 /* set up the email headers */
333 time (&t);
334 tm = *gmtime (&t);
335 strftime (timebuf, sizeof (timebuf) - 1, "%a, %d %b %Y %H:%M:%S +0000", &tm);
336
337 date = timebuf;
338
339 snprintf (from, sizeof from, "%s automailer <noreply.%s>", me.netname, me.adminemail);
340 snprintf (to, sizeof to, "%s <%s>", mu->name, email);
341
342 strlcpy (subject, me.netname, sizeof subject);
343 strlcat (subject, " ", sizeof subject);
344 if (type == EMAIL_REGISTER)
345 if (nicksvs.no_nick_ownership)
346 strlcat (subject, "Account Registration", sizeof subject);
347 else
348 strlcat (subject, "Nickname Registration", sizeof subject);
349 else if (type == EMAIL_SENDPASS || type == EMAIL_SETPASS)
350 strlcat (subject, "Password Retrieval", sizeof subject);
351 else if (type == EMAIL_SETEMAIL)
352 strlcat (subject, "Change Email Confirmation", sizeof subject);
353 else if (type == EMAIL_MEMO)
354 strlcat (subject, "New memo", sizeof subject);
355
356 /* now set up the email */
357 sprintf (cmdbuf, "%s %s", me.mta, email);
358 if (pipe (pipfds) < 0)
359 return 0;
360 switch (pid = fork ())
361 {
362 case -1:
363 return 0;
364 case 0:
365 close (pipfds[1]);
366 dup2 (pipfds[0], 0);
367 switch (fork ())
368 {
369 /* fork again to avoid zombies -- jilles */
370 case -1:
371 _exit (255);
372 case 0:
373 execl ("/bin/sh", "sh", "-c", cmdbuf, NULL);
374 _exit (255);
375 default:
376 _exit (0);
377 }
378 }
379 close (pipfds[0]);
380 waitpid (pid, &status, 0);
381 out = fdopen (pipfds[1], "w");
382
383 fprintf (out, "From: %s\n", from);
384 fprintf (out, "To: %s\n", to);
385 fprintf (out, "Subject: %s\n", subject);
386 fprintf (out, "Date: %s\n\n", date);
387
388 fprintf (out, "%s,\n\n", mu->name);
389
390 if (type == EMAIL_REGISTER)
391 {
392 fprintf (out, "In order to complete your registration, you must send the following\ncommand on IRC:\n");
393 fprintf (out, "/MSG %s VERIFY REGISTER %s %s\n\n", nicksvs.nick, mu->name, param);
394 fprintf (out, "Thank you for registering your %s on the %s IRC " "network!\n\n", (nicksvs.no_nick_ownership ? "account" : "nickname"), me.netname);
395 }
396 else if (type == EMAIL_SENDPASS)
397 {
398 fprintf (out, "Someone has requested the password for %s be sent to the\n" "corresponding email address. If you did not request this action\n" "please let us know.\n\n", mu->name);
399 fprintf (out, "The password for %s is %s. Please write this down for " "future reference.\n\n", mu->name, param);
400 }
401 else if (type == EMAIL_SETEMAIL)
402 {
403 fprintf (out, "In order to complete your email change, you must send\n" "the following command on IRC:\n");
404 fprintf (out, "/MSG %s VERIFY EMAILCHG %s %s\n\n", nicksvs.nick, mu->name, param);
405 }
406 else if (type == EMAIL_MEMO)
407 {
408 if (u->myuser != NULL)
409 fprintf (out, "You have a new memo from %s.\n\n", u->myuser->name);
410 else
411 /* shouldn't happen */
412 fprintf (out, "You have a new memo from %s (unregistered?).\n\n", u->nick);
413 fprintf (out, "%s\n\n", param);
414 }
415 else if (type == EMAIL_SETPASS)
416 {
417 fprintf (out, "In order to set a new password, you must send\n" "the following command on IRC:\n");
418 fprintf (out, "/MSG %s SETPASS %s %s <password>\nwhere <password> is your desired new password.\n\n", nicksvs.nick, mu->name, param);
419 }
420
421 fprintf (out, "Thank you for your interest in the %s IRC network.\n", me.netname);
422 if (u->server != me.me)
423 fprintf (out, "\nThis email was sent due to a command from %s[%s@%s]\nat %s.\n", u->nick, u->user, u->vhost, date);
424 fprintf (out, "If this message is spam, please contact %s\nwith a full copy.\n", me.adminemail);
425 fprintf (out, ".\n");
426 rc = 1;
427 if (ferror (out))
428 rc = 0;
429 if (fclose (out) < 0)
430 rc = 0;
431 if (rc == 0)
432 slog (LG_ERROR, "sendemail(): mta failure");
433 return rc;
434 }
435
436 /* various access level checkers */
437 bool
438 myuser_t::is_founder (mychan_t *mc) const
439 {
440 if (chanacs_find (mc, this, CA_FOUNDER))
441 return true;
442
443 return false;
444 }
445
446 bool
447 myuser_t::should_owner (mychan_t *mc) const
448 {
449 if (MC_NOOP & mc->flags)
450 return false;
451
452 if (MU_NOOP & flags)
453 return false;
454
455 if (is_founder (mc))
456 return true;
457
458 return false;
459 }
460
461 bool
462 myuser_t::should_protect (mychan_t *mc) const
463 {
464 if (MC_NOOP & mc->flags)
465 return false;
466
467 if (MU_NOOP & flags)
468 return false;
469
470 if (chanacs_find (mc, this, CA_SET))
471 return true;
472
473 return false;
474 }
475
476 bool
477 is_ircop (user_t *user)
478 {
479 if (UF_IRCOP & user->flags)
480 return true;
481
482 return false;
483 }
484
485 bool
486 is_admin (user_t *user)
487 {
488 if (UF_ADMIN & user->flags)
489 return true;
490
491 return false;
492 }
493
494 void
495 myuser_t::set_password (char const * const newpassword)
496 {
497 if (newpassword == NULL)
498 return;
499
500 /* if we can, try to crypt it */
501 if (crypto::handler::loaded)
502 {
503 flags |= MU_CRYPTPASS;
504 strlcpy (pass, crypter->crypt (newpassword, crypto::gen_salt ()), NICKLEN);
505 }
506 else
507 {
508 flags &= ~MU_CRYPTPASS; /* just in case */
509 strlcpy (pass, newpassword, NICKLEN);
510 }
511 }
512
513 bool
514 myuser_t::verify_password (char const * const password) const
515 {
516 if (password == NULL)
517 return false;
518
519 if (flags & MU_CRYPTPASS)
520 if (crypto::handler::loaded)
521 return crypto::verify_password (password, pass);
522 else
523 { /* not good! */
524 slog (LG_ERROR, "check_password(): can't check crypted password -- no crypto module!");
525 return false;
526 }
527 else
528 return (strcmp (pass, password) == 0);
529 }
530
531 char const *
532 sbytes (float x)
533 {
534 if (x > 1073741824.0)
535 return "GB";
536
537 else if (x > 1048576.0)
538 return "MB";
539
540 else if (x > 1024.0)
541 return "KB";
542
543 return "B";
544 }
545
546 float
547 bytes (float x)
548 {
549 if (x > 1073741824.0)
550 return (x / 1073741824.0);
551
552 if (x > 1048576.0)
553 return (x / 1048576.0);
554
555 if (x > 1024.0)
556 return (x / 1024.0);
557
558 return x;
559 }