ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/function.C
Revision: 1.8
Committed: Sun Sep 16 18:54:45 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.7: +7 -3 lines
Log Message:
#defines to enum

File Contents

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