fix possible crash on user deletion
[srvx.git] / src / mail-common.c
1 /* mail-common.c - mail sending utilities
2  * Copyright 2002-2004, 2007 srvx Development Team
3  *
4  * This file is part of srvx.
5  *
6  * srvx is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (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 srvx; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
19  */
20
21 #include "conf.h"
22 #include "modcmd.h"
23 #include "nickserv.h"
24 #include "saxdb.h"
25
26 #ifdef HAVE_SYS_WAIT_H
27 #include <sys/wait.h>
28 #endif
29
30 #define KEY_PROHIBITED   "prohibited"
31
32 static const struct message_entry msgtab[] = {
33     { "MAILMSG_EMAIL_ALREADY_BANNED", "%s is already banned (%s)." },
34     { "MAILMSG_EMAIL_BANNED", "Email to %s has been forbidden." },
35     { "MAILMSG_EMAIL_NOT_BANNED", "Email to %s was not forbidden." },
36     { "MAILMSG_EMAIL_UNBANNED", "Email to %s is now allowed." },
37     { "MAILMSG_PROHIBITED_EMAIL", "%s: %s" },
38     { "MAILMSG_NO_PROHIBITED_EMAIL", "All email addresses are accepted." },
39     { NULL, NULL }
40 };
41
42 static dict_t prohibited_addrs, prohibited_masks;
43 struct module *mail_module;
44
45 const char *
46 mail_prohibited_address(const char *addr)
47 {
48     dict_iterator_t it;
49     const char *data;
50
51     if (prohibited_addrs && (data = dict_find(prohibited_addrs, addr, NULL)))
52         return data;
53     if (prohibited_masks)
54         for (it = dict_first(prohibited_masks); it; it = iter_next(it))
55             if (match_ircglob(addr, iter_key(it)))
56                 return iter_data(it);
57     return NULL;
58 }
59
60 static int
61 mail_ban_address(struct userNode *user, struct userNode *bot, const char *addr, const char *reason) {
62     dict_t target;
63     const char *str;
64
65     target = strpbrk(addr, "*?") ? prohibited_masks : prohibited_addrs;
66     if ((str = dict_find(target, addr, NULL))) {
67         if (user)
68             send_message(user, bot, "MAILMSG_EMAIL_ALREADY_BANNED", addr, str);
69         return 0;
70     }
71     dict_insert(target, strdup(addr), strdup(reason));
72     if (user) send_message(user, bot, "MAILMSG_EMAIL_BANNED", addr);
73     return 1;
74 }
75
76 static MODCMD_FUNC(cmd_banemail) {
77     char *reason = unsplit_string(argv+2, argc-2, NULL);
78     return mail_ban_address(user, cmd->parent->bot, argv[1], reason);
79 }
80
81 static MODCMD_FUNC(cmd_unbanemail) {
82     dict_t target;
83     const char *addr;
84
85     addr = argv[1];
86     target = strpbrk(addr, "*?") ? prohibited_masks : prohibited_addrs;
87     if (dict_remove(target, addr))
88         reply("MAILMSG_EMAIL_UNBANNED", addr);
89     else
90         reply("MAILMSG_EMAIL_NOT_BANNED", addr);
91     return 1;
92 }
93
94 static MODCMD_FUNC(cmd_stats_email) {
95     dict_iterator_t it;
96     int found = 0;
97
98     for (it=dict_first(prohibited_addrs); it; it=iter_next(it)) {
99         reply("MAILMSG_PROHIBITED_EMAIL", iter_key(it), (const char*)iter_data(it));
100         found = 1;
101     }
102     for (it=dict_first(prohibited_masks); it; it=iter_next(it)) {
103         reply("MAILMSG_PROHIBITED_EMAIL", iter_key(it), (const char*)iter_data(it));
104         found = 1;
105     }
106     if (!found)
107         reply("MAILMSG_NO_PROHIBITED_EMAIL");
108     return 0;
109 }
110
111 static int
112 mail_saxdb_read(struct dict *db) {
113     struct dict *subdb;
114     struct record_data *rd;
115     dict_iterator_t it;
116
117     if ((subdb = database_get_data(db, KEY_PROHIBITED, RECDB_OBJECT))) {
118         for (it = dict_first(subdb); it; it = iter_next(it)) {
119             rd = iter_data(it);
120             if (rd->type == RECDB_QSTRING)
121                 mail_ban_address(NULL, NULL, iter_key(it), rd->d.qstring);
122         }
123     }
124     return 0;
125 }
126
127 static int
128 mail_saxdb_write(struct saxdb_context *ctx) {
129     dict_iterator_t it;
130
131     saxdb_start_record(ctx, KEY_PROHIBITED, 0);
132     for (it = dict_first(prohibited_masks); it; it = iter_next(it))
133         saxdb_write_string(ctx, iter_key(it), iter_data(it));
134     for (it = dict_first(prohibited_addrs); it; it = iter_next(it))
135         saxdb_write_string(ctx, iter_key(it), iter_data(it));
136     saxdb_end_record(ctx);
137     return 0;
138 }
139
140 static void
141 mail_common_cleanup(void)
142 {
143     dict_delete(prohibited_addrs);
144     dict_delete(prohibited_masks);
145 }
146
147 static void
148 mail_common_init(void)
149 {
150     prohibited_addrs = dict_new();
151     dict_set_free_keys(prohibited_addrs, free);
152     dict_set_free_data(prohibited_addrs, free);
153     prohibited_masks = dict_new();
154     dict_set_free_keys(prohibited_masks, free);
155     dict_set_free_data(prohibited_masks, free);
156     reg_exit_func(mail_common_cleanup);
157     saxdb_register("sendmail", mail_saxdb_read, mail_saxdb_write);
158     mail_module = module_register("sendmail", MAIN_LOG, "mail.help", NULL);
159     modcmd_register(mail_module, "banemail", cmd_banemail, 3, 0, "level", "601", NULL);
160     modcmd_register(mail_module, "stats email", cmd_stats_email, 0, 0, "flags", "+oper", NULL);
161     modcmd_register(mail_module, "unbanemail", cmd_unbanemail, 2, 0, "level", "601", NULL);
162     message_register_table(msgtab);
163 }