1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
|
/* MemoServ functions.
*
* (C) 2003-2012 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
*
*/
#include "services.h"
#include "pseudo.h"
/*************************************************************************/
/* *INDENT-OFF* */
E void moduleAddMemoServCmds(void);
static void new_memo_mail(NickCore *nc, Memo *m);
E void rsend_notify(User *u, Memo *m, const char *chan);
/*************************************************************************/
void moduleAddMemoServCmds(void) {
modules_core_init(MemoServCoreNumber, MemoServCoreModules);
}
/*************************************************************************/
/*************************************************************************/
/* *INDENT-ON* */
/**
* MemoServ initialization.
* @return void
*/
void ms_init(void)
{
moduleAddMemoServCmds();
}
/*************************************************************************/
/**
* memoserv: Main MemoServ routine.
* Note that the User structure passed to the do_* routines will
* always be valid (non-NULL) and will always have a valid
* NickInfo pointer in the `ni' field.
* @param u User Struct
* @param buf Buffer containing the privmsg
* @return void
*/
void memoserv(User * u, char *buf)
{
char *cmd, *s;
cmd = strtok(buf, " ");
if (!cmd) {
return;
} else if (stricmp(cmd, "\1PING") == 0) {
if (!(s = strtok(NULL, ""))) {
s = "";
}
anope_cmd_ctcp(s_MemoServ, u->nick, "PING %s", s);
} else if (skeleton) {
notice_lang(s_MemoServ, u, SERVICE_OFFLINE, s_MemoServ);
} else {
if (!u->na && stricmp(cmd, "HELP") != 0)
notice_lang(s_MemoServ, u, NICK_NOT_REGISTERED_HELP,
s_NickServ);
else
mod_run_cmd(s_MemoServ, u, MEMOSERV, cmd);
}
}
/*************************************************************************/
/**
* check_memos: See if the given user has any unread memos, and send a
* NOTICE to that user if so (and if the appropriate flag is
* set).
* @param u User Struct
* @return void
*/
void check_memos(User * u)
{
NickCore *nc;
int i, newcnt = 0;
if (!u) {
if (debug) {
alog("debug: check_memos called with NULL values");
}
return;
}
if (!(nc = (u->na ? u->na->nc : NULL)) || !nick_recognized(u) ||
!(nc->flags & NI_MEMO_SIGNON)) {
return;
}
for (i = 0; i < nc->memos.memocount; i++) {
if (nc->memos.memos[i].flags & MF_UNREAD)
newcnt++;
}
if (newcnt > 0) {
notice_lang(s_MemoServ, u,
newcnt == 1 ? MEMO_HAVE_NEW_MEMO : MEMO_HAVE_NEW_MEMOS,
newcnt);
if (newcnt == 1 && (nc->memos.memos[i - 1].flags & MF_UNREAD)) {
notice_lang(s_MemoServ, u, MEMO_TYPE_READ_LAST, s_MemoServ);
} else if (newcnt == 1) {
for (i = 0; i < nc->memos.memocount; i++) {
if (nc->memos.memos[i].flags & MF_UNREAD)
break;
}
notice_lang(s_MemoServ, u, MEMO_TYPE_READ_NUM, s_MemoServ,
nc->memos.memos[i].number);
} else {
notice_lang(s_MemoServ, u, MEMO_TYPE_LIST_NEW, s_MemoServ);
}
}
if (nc->memos.memomax > 0 && nc->memos.memocount >= nc->memos.memomax) {
if (nc->memos.memocount > nc->memos.memomax)
notice_lang(s_MemoServ, u, MEMO_OVER_LIMIT, nc->memos.memomax);
else
notice_lang(s_MemoServ, u, MEMO_AT_LIMIT, nc->memos.memomax);
}
}
/*************************************************************************/
/*********************** MemoServ private routines ***********************/
/*************************************************************************/
/**
* Return the MemoInfo corresponding to the given nick or channel name.
* @param name Name to check
* @param ischan - the result its a channel will be stored in here
* @param isforbid - the result if its forbidden will be stored in here
* @return `ischan' 1 if the name was a channel name, else 0.
* @return `isforbid' 1 if the name is forbidden, else 0.
*/
MemoInfo *getmemoinfo(const char *name, int *ischan, int *isforbid)
{
if (*name == '#') {
ChannelInfo *ci;
if (ischan)
*ischan = 1;
ci = cs_findchan(name);
if (ci) {
if (!(ci->flags & CI_VERBOTEN)) {
*isforbid = 0;
return &ci->memos;
} else {
*isforbid = 1;
return NULL;
}
} else {
*isforbid = 0;
return NULL;
}
} else {
NickAlias *na;
if (ischan)
*ischan = 0;
na = findnick(name);
if (na) {
if (!(na->status & NS_VERBOTEN)) {
*isforbid = 0;
return &na->nc->memos;
} else {
*isforbid = 1;
return NULL;
}
} else {
*isforbid = 0;
return NULL;
}
}
}
/*************************************************************************/
/**
* Split from do_send, this way we can easily send a memo from any point.
*
* @param u User Struct
* @param name Target of the memo
* @param text Memo Text
* @param z type see info
* 0 - reply to user
* 1 - silent
* 2 - silent with no delay timer
* 3 - reply to user and request read receipt
* @return void
*/
void memo_send(User * u, char *name, char *text, int z)
{
memo_send_from(u, name, text, z, u->na->nc->display);
}
/**
* Split from do_send, this way we can easily send a memo from any point.
*
* @param u User Struct
* @param name Target of the memo
* @param text Memo Text
* @param z type see info
* @param source Nickname of the alias the memo originates from.
* 0 - reply to user
* 1 - silent
* 2 - silent with no delay timer
* 3 - reply to user and request read receipt
* @return void
*/
void memo_send_from(User * u, char *name, char *text, int z, char *source)
{
int ischan;
int isforbid;
Memo *m;
MemoInfo *mi;
time_t now = time(NULL);
int is_servoper = is_services_oper(u);
if (readonly) {
notice_lang(s_MemoServ, u, MEMO_SEND_DISABLED);
} else if (checkDefCon(DEFCON_NO_NEW_MEMOS)) {
notice_lang(s_MemoServ, u, OPER_DEFCON_DENIED);
return;
} else if (!text) {
if (z == 0)
syntax_error(s_MemoServ, u, "SEND", MEMO_SEND_SYNTAX);
if (z == 3)
syntax_error(s_MemoServ, u, "RSEND", MEMO_RSEND_SYNTAX);
} else if (!nick_recognized(u)) {
if (z == 0 || z == 3)
notice_lang(s_MemoServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);
} else if (!(mi = getmemoinfo(name, &ischan, &isforbid))) {
if (z == 0 || z == 3) {
if (isforbid) {
notice_lang(s_MemoServ, u,
ischan ? CHAN_X_FORBIDDEN :
NICK_X_FORBIDDEN, name);
} else {
notice_lang(s_MemoServ, u,
ischan ? CHAN_X_NOT_REGISTERED :
NICK_X_NOT_REGISTERED, name);
}
}
} else if (z != 2 && MSSendDelay > 0 &&
u && u->lastmemosend + MSSendDelay > now && !is_servoper) {
u->lastmemosend = now;
if (z == 0)
notice_lang(s_MemoServ, u, MEMO_SEND_PLEASE_WAIT, MSSendDelay);
if (z == 3)
notice_lang(s_MemoServ, u, MEMO_RSEND_PLEASE_WAIT,
MSSendDelay);
} else if (mi->memomax == 0 && !is_servoper) {
if (z == 0 || z == 3)
notice_lang(s_MemoServ, u, MEMO_X_GETS_NO_MEMOS, name);
} else if (mi->memocount >= 32767 || (mi->memomax > 0 && mi->memocount >= mi->memomax
&& !is_servoper)) {
if (z == 0 || z == 3)
notice_lang(s_MemoServ, u, MEMO_X_HAS_TOO_MANY_MEMOS, name);
} else {
u->lastmemosend = now;
mi->memocount++;
mi->memos = srealloc(mi->memos, sizeof(Memo) * mi->memocount);
m = &mi->memos[mi->memocount - 1];
strscpy(m->sender, source, NICKMAX);
m->moduleData = NULL;
if (mi->memocount > 1) {
m->number = m[-1].number + 1;
if (m->number < 1) {
int i;
for (i = 0; i < mi->memocount; i++) {
mi->memos[i].number = i + 1;
}
}
} else {
m->number = 1;
}
m->time = time(NULL);
m->text = sstrdup(text);
m->flags = MF_UNREAD;
#ifdef USE_MYSQL
m->id = 0;
#endif
/* Set notify sent flag - DrStein */
if (z == 2) {
m->flags |= MF_NOTIFYS;
}
/* Set receipt request flag */
if (z == 3)
m->flags |= MF_RECEIPT;
if (z == 0 || z == 3)
notice_lang(s_MemoServ, u, MEMO_SENT, name);
if (!ischan) {
NickAlias *na;
NickCore *nc = (findnick(name))->nc;
if (MSNotifyAll) {
if ((nc->flags & NI_MEMO_RECEIVE)
&& get_ignore(name) == NULL) {
int i;
for (i = 0; i < nc->aliases.count; i++) {
na = nc->aliases.list[i];
if (na->u && nick_identified(na->u))
notice_lang(s_MemoServ, na->u,
MEMO_NEW_MEMO_ARRIVED, source,
s_MemoServ, m->number);
}
} else {
if ((u = finduser(name)) && nick_identified(u)
&& (nc->flags & NI_MEMO_RECEIVE))
notice_lang(s_MemoServ, u, MEMO_NEW_MEMO_ARRIVED,
source, s_MemoServ, m->number);
} /* if (flags & MEMO_RECEIVE) */
}
/* if (MSNotifyAll) */
/* let's get out the mail if set in the nickcore - certus */
if (nc->flags & NI_MEMO_MAIL)
new_memo_mail(nc, m);
} else {
struct c_userlist *cu, *next;
Channel *c;
if (MSNotifyAll && (c = findchan(name))) {
for (cu = c->users; cu; cu = next) {
next = cu->next;
if (check_access(cu->user, c->ci, CA_MEMO)) {
if (cu->user->na
&& (cu->user->na->nc->flags & NI_MEMO_RECEIVE)
&& get_ignore(cu->user->nick) == NULL) {
notice_lang(s_MemoServ, cu->user,
MEMO_NEW_X_MEMO_ARRIVED,
c->ci->name, s_MemoServ,
c->ci->name, m->number);
}
}
}
} /* MSNotifyAll */
} /* if (!ischan) */
} /* if command is valid */
}
/*************************************************************************/
/**
* Delete a memo by number.
* @param mi Memoinfo struct
* @param num Memo number to delete
* @return int 1 if the memo was found, else 0.
*/
int delmemo(MemoInfo * mi, int num)
{
int i;
for (i = 0; i < mi->memocount; i++) {
if (mi->memos[i].number == num)
break;
}
if (i < mi->memocount) {
moduleCleanStruct(&mi->memos[i].moduleData);
free(mi->memos[i].text); /* Deallocate memo text memory */
mi->memocount--; /* One less memo now */
if (i < mi->memocount) /* Move remaining memos down a slot */
memmove(mi->memos + i, mi->memos + i + 1,
sizeof(Memo) * (mi->memocount - i));
if (mi->memocount == 0) { /* If no more memos, free array */
free(mi->memos);
mi->memos = NULL;
}
return 1;
} else {
return 0;
}
}
/*************************************************************************/
static void new_memo_mail(NickCore * nc, Memo * m)
{
MailInfo *mail = NULL;
if (!nc || !m)
return;
mail = MailMemoBegin(nc);
if (!mail) {
return;
}
fprintf(mail->pipe, getstring2(NULL, MEMO_MAIL_TEXT1), nc->display);
fprintf(mail->pipe, "\n");
fprintf(mail->pipe, getstring2(NULL, MEMO_MAIL_TEXT2), m->sender,
m->number);
fprintf(mail->pipe, "\n\n");
fprintf(mail->pipe, "%s", getstring2(NULL, MEMO_MAIL_TEXT3));
fprintf(mail->pipe, "\n\n");
fprintf(mail->pipe, "%s", m->text);
fprintf(mail->pipe, "\n");
MailEnd(mail);
return;
}
/*************************************************************************/
/* Send receipt notification to sender. */
void rsend_notify(User * u, Memo * m, const char *chan)
{
NickAlias *na;
NickCore *nc;
char text[256];
const char *fmt;
/* Only send receipt if memos are allowed */
if ((!readonly) && (!checkDefCon(DEFCON_NO_NEW_MEMOS))) {
/* Get nick alias for sender */
na = findnick(m->sender);
if (!na) {
return;
}
/* Get nick core for sender */
nc = na->nc;
if (!nc) {
return;
}
/* Text of the memo varies if the recepient was a
nick or channel */
if (chan) {
fmt = getstring(na, MEMO_RSEND_CHAN_MEMO_TEXT);
snprintf(text, sizeof(text), fmt, chan);
} else {
fmt = getstring(na, MEMO_RSEND_NICK_MEMO_TEXT);
snprintf(text, sizeof(text), "%s", fmt);
}
/* Send notification */
memo_send(u, m->sender, text, 2);
/* Notify recepient of the memo that a notification has
been sent to the sender */
notice_lang(s_MemoServ, u, MEMO_RSEND_USER_NOTIFICATION,
nc->display);
}
/* Remove receipt flag from the original memo */
m->flags &= ~MF_RECEIPT;
return;
}
|