readmail.cpp 22.9 KB
Newer Older
1
2
3
4
5
6
/* Synchronet private mail reading function */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
7
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"

24
25
26
static char mail_listing_flag(smbmsg_t* msg)
{
	if(msg->hdr.attr&MSG_DELETE)				return '-';
27
	if(msg->hdr.attr&MSG_SPAM)					return 'S';
28
29
30
31
32
33
34
35
36
37
38
	if(msg->hdr.attr&MSG_REPLIED)				return 'R';
	if(msg->hdr.attr&MSG_READ)					return ' ';
	if(msg->hdr.attr&MSG_PERMANENT)				return 'p';
	if(msg->hdr.attr&MSG_LOCKED)				return 'L';
	if(msg->hdr.attr&MSG_KILLREAD)				return 'K';
	if(msg->hdr.attr&MSG_NOREPLY)				return '#';
	if(msg->from_net.type || msg->to_net.type)	return 'N';
	if(msg->hdr.attr&MSG_ANONYMOUS)				return 'A';
	return '*';
}

39
40
41
/****************************************************************************/
/* Reads mail waiting for usernumber.                                       */
/****************************************************************************/
rswindell's avatar
rswindell committed
42
void sbbs_t::readmail(uint usernumber, int which, long lm_mode)
43
{
44
45
	char	str[256],str2[256],done=0,domsg=1
			,*p;
46
	char 	tmp[512];
47
48
	int		i;
	uint32_t u,v;
49
	int		mismatches=0,act;
50
	uint	unum;
51
    long    l,last_mode;
52
53
54
55
	ulong	last;
	bool	replied;
	mail_t	*mail;
	smbmsg_t msg;
56
	char search_str[128] = "";
57

58
59
60
61
62
63
64
65
	if(which==MAIL_SENT)
		act=NODE_RSML;
	else if(which==MAIL_ALL)
		act=NODE_SYSP;
	else
		act=NODE_RMAL;
	action=act;

66
67
68
69
	if(cfg.readmail_mod[0] && !readmail_inside) {
		char cmdline[256];

		readmail_inside = true;
rswindell's avatar
rswindell committed
70
		safe_snprintf(cmdline, sizeof(cmdline), "%s %d %u %lu", cfg.readmail_mod, which, usernumber, lm_mode);
71
72
73
74
75
		exec_bin(cmdline, &main_csi);
		readmail_inside = false;
		return;
	}

76
77
78
79
80
	if(which==MAIL_SENT && useron.rest&FLAG('K')) {
		bputs(text[R_ReadSentMail]);
		return;
	}

81
82
83
84
	msg.total_hfields=0;			/* init to NULL, cause not allocated yet */

	if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
		errormsg(WHERE,ERR_OPEN,"MAIL",i);
85
86
		return; 
	}
87
	SAFEPRINTF(smb.file,"%smail",cfg.data_dir);
88
	smb.retry_time=cfg.smb_retry_time;
89
	smb.subnum=INVALID_SUB;
90
91
92
	if((i=smb_open(&smb))!=0) {
		smb_stack(&smb,SMB_STACK_POP);
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
93
94
		return; 
	}
95
96

	if(cfg.sys_misc&SM_SYSVDELM && (SYSOP || cfg.sys_misc&SM_USRVDELM))
rswindell's avatar
rswindell committed
97
		lm_mode |= LM_INCDEL;
98
	mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
99
	last_mode = lm_mode;
100
	if(!smb.msgs) {
101
102
103
104
105
		if(which==MAIL_SENT)
			bputs(text[NoMailSent]);
		else if(which==MAIL_ALL)
			bputs(text[NoMailOnSystem]);
		else
rswindell's avatar
rswindell committed
106
			bprintf(text[NoMailWaiting], lm_mode&LM_UNREAD ? "un-read mail" : "mail");
107
108
		smb_close(&smb);
		smb_stack(&smb,SMB_STACK_POP);
109
110
		return; 
	}
111
112
113

	last=smb.status.last_msg;

114
	const char* order = (lm_mode&LM_REVERSE) ? "newest" : "oldest";
115
	if(smb.msgs>1 && which!=MAIL_ALL) {
116
		if(which==MAIL_SENT)
117
			bprintf(text[MailSentLstHdr], order);
118
		else
119
			bprintf(text[MailWaitingLstHdr], order);
120

121
		for(smb.curmsg=0;smb.curmsg<smb.msgs && !msgabort();smb.curmsg++) {
122
123
124
			if(msg.total_hfields)
				smb_freemsgmem(&msg);
			msg.total_hfields=0;
125
			msg.idx.offset=mail[smb.curmsg].offset;
126
			if(loadmsg(&msg,mail[smb.curmsg].number) < 1)
127
128
				continue;
			smb_unlockmsghdr(&smb,&msg);
rswindell's avatar
rswindell committed
129
130
			bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
				,msghdr_text(&msg, MailWaitingLstFmt), smb.curmsg+1
131
132
133
				,which==MAIL_SENT ? msg.to
				: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP ? text[Anonymous]
				: msg.from
134
				,mail_listing_flag(&msg)
135
136
				,msg.subj);
			smb_freemsgmem(&msg);
137
138
			msg.total_hfields=0; 
		}
139
140

		ASYNC;
141
142
143
144
		if(sys_status&SS_ABORT) {
			domsg=0;
			smb.curmsg=0;
		} else {
145
			bprintf(text[StartWithN],1L);
146
147
148
149
			l=getnum(smb.msgs);
			if(l>0)
				smb.curmsg=l-1;
			else if(l==-1) {
deuce's avatar
deuce committed
150
				free(mail);
151
152
				smb_close(&smb);
				smb_stack(&smb,SMB_STACK_POP);
153
				return;
154
			}
155
156
			else
				smb.curmsg=l;
157
158
159
		}
		sys_status&=~SS_ABORT; 
	}
160
	else {
161
		smb.curmsg=0;
162
		if(which==MAIL_ALL)
163
164
			domsg=0; 
	}
165
	if(which==MAIL_SENT) {
166
		logline("E","read sent mail");
167
	} else if(which==MAIL_ALL) {
168
		logline("S+","read all mail");
169
	} else {
170
		logline("E","read mail");
171
	}
rswindell's avatar
rswindell committed
172
173
174
	const char* menu_file = (which == MAIL_ALL ? "allmail" : which==MAIL_SENT ? "sentmail" : "mailread");
	if(useron.misc&RIP)
		menu(menu_file); 
175
	current_msg=&msg;	/* For MSG_* @-codes and bbs.msg_* property values */
176
177
178
179
180
181
182
	while(online && !done) {
		action=act;

		if(msg.total_hfields)
			smb_freemsgmem(&msg);
		msg.total_hfields=0;

183
184
185
186
187
		msg.idx.offset=mail[smb.curmsg].offset;
		msg.idx.number=mail[smb.curmsg].number;
		msg.idx.to=mail[smb.curmsg].to;
		msg.idx.from=mail[smb.curmsg].from;
		msg.idx.subj=mail[smb.curmsg].subj;
188
189

		if((i=smb_locksmbhdr(&smb))!=0) {
190
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
191
192
			break; 
		}
193
194
195

		if((i=smb_getstatus(&smb))!=0) {
			smb_unlocksmbhdr(&smb);
196
			errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
197
198
			break; 
		}
199
200
		smb_unlocksmbhdr(&smb);

201
		if(smb.status.last_msg!=last || lm_mode != last_mode) { 	/* New messages */
202
			last=smb.status.last_msg;
deuce's avatar
deuce committed
203
			free(mail);
204
			order = (lm_mode&LM_REVERSE) ? "newest" : "oldest";
205
206
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);   /* So re-load */
			if(!smb.msgs)
207
				break;
208
209
210
211
212
213
214
215
216
			if(lm_mode != last_mode)
				smb.curmsg = 0;
			else {
				for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
					if(mail[smb.curmsg].number==msg.idx.number)
						break;
				if(smb.curmsg>=smb.msgs)
					smb.curmsg=(smb.msgs-1);
			}
217
			last_mode = lm_mode;
218
219
			continue; 
		}
220

221
		if(loadmsg(&msg,mail[smb.curmsg].number) < 0) {	/* Message header gone */
222
			if(mismatches>5) {	/* We can't do this too many times in a row */
223
				errormsg(WHERE,ERR_CHK,"message number",mail[smb.curmsg].number);
224
225
				break; 
			}
deuce's avatar
deuce committed
226
			free(mail);
227
228
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
			if(!smb.msgs)
229
				break;
230
			last_mode = lm_mode;
231
232
			if(smb.curmsg>(smb.msgs-1))
				smb.curmsg=(smb.msgs-1);
233
			mismatches++;
234
235
			continue; 
		}
236
237
238
239
240
241
242
		smb_unlockmsghdr(&smb,&msg);
		msg.idx.attr=msg.hdr.attr;

		mismatches=0;

		if(domsg && !(sys_status&SS_ABORT)) {

243
			if(!show_msg(&smb, &msg
244
				,msg.from_ext && msg.idx.from==1 && !msg.from_net.type
245
246
					? 0:P_NOATCODES))
				errormsg(WHERE,"showing", "mail message", msg.hdr.number, smb.last_error);
247
			download_msg_attachments(&smb, &msg, which == MAIL_YOUR);
248
			if(which==MAIL_YOUR && !(msg.hdr.attr&MSG_READ)) {
249
				mail[smb.curmsg].attr|=MSG_READ;
250
251
252
253
254
255
				if(thisnode.status==NODE_INUSE)
					telluser(&msg);
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;						/* Search by number */
256
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
257
					if(loadmsg(&msg,msg.idx.number) >= 0) {
258
						msg.hdr.attr|=MSG_READ;
259
260
						if(msg.hdr.attr&MSG_KILLREAD)
							msg.hdr.attr|=MSG_DELETE;
261
262
						msg.idx.attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
263
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
264
265
266
267
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb); 
				}
268
269
				if(!msg.total_hfields) {				/* unsuccessful reload */
					domsg=0;
270
271
					continue; 
				}
272
			}
273
		}
274
275
		else domsg=1;

rswindell's avatar
rswindell committed
276
277
		if(useron.misc&WIP)
			menu(menu_file); 
278
279
280

		ASYNC;
		if(which==MAIL_SENT)
281
			bprintf(text[ReadingSentMail],smb.curmsg+1,smb.msgs);
282
		else if(which==MAIL_ALL)
283
			bprintf(text[ReadingAllMail],smb.curmsg+1,smb.msgs);
284
		else
285
			bprintf(text[ReadingMail],smb.curmsg+1,smb.msgs);
286
287
288
289
290
		sprintf(str,"ADFLNQRT?<>[]{}()-+/!%c%c%c%c"
			,TERM_KEY_LEFT
			,TERM_KEY_RIGHT
			,TERM_KEY_HOME
			,TERM_KEY_END);
291
		if(SYSOP)
292
			strcat(str,"CUSPH");
293
294
295
296
297
298
		if(which == MAIL_YOUR)
			strcat(str,"K");	// kill all (visible)
		else
			strcat(str,"E");	// edit msg
		if(which != MAIL_SENT)
			strcat(str,"V");	// View SPAM toggle
299
		l=getkeys(str,smb.msgs);
300
301
302
		if(l&0x80000000L) {
			if(l==-1)	/* ctrl-c */
				break;
303
			smb.curmsg=(l&~0x80000000L)-1;
304
305
			continue; 
		}
306
		switch(l) {
307
308
309
310
			case '!':
				lm_mode ^= LM_REVERSE;
				domsg=0;
				break;
311
312
313
314
315
316
317
			case 'A':   /* Auto-reply to last piece */
			case 'R':
				if(l==(cfg.sys_misc&SM_RA_EMU ? 'A' : 'R'))  /* re-read last message */
					break;

				if(which==MAIL_SENT)
					break;
318
319
				if((msg.hdr.attr&(MSG_NOREPLY|MSG_ANONYMOUS)) && !SYSOP) {
					bputs(text[CantReplyToMsg]);
320
321
					break; 
				}
322

323
				if(msg.from_net.addr==NULL)
324
					SAFECOPY(str,msg.from);
325
				else if(msg.from_net.type==NET_FIDO) 	/* FidoNet type */
326
					SAFEPRINTF2(str,"%s@%s",msg.from
327
						,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
328
				else if(msg.from_net.type==NET_INTERNET || strchr((char*)msg.from_net.addr,'@')!=NULL) {
329
330
331
332
333
334
335
336
					if(msg.replyto_net.type==NET_INTERNET)
						SAFECOPY(str,(char *)msg.replyto_net.addr);
					else
						SAFECOPY(str,(char *)msg.from_net.addr);
				} else
					SAFEPRINTF2(str,"%s@%s",msg.from,(char*)msg.from_net.addr);

				SAFECOPY(str2,str);
337
338
339
340
341
342
343
344

				bputs(text[Email]);
				if(!getstr(str,64,K_EDIT|K_AUTODEL))
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);

				if(!stricmp(str2,str))		/* Reply to sender */
rswindell's avatar
rswindell committed
345
					SAFEPRINTF(str2,text[Regarding], msghdr_field(&msg, msg.subj));
346
				else						/* Reply to other */
rswindell's avatar
rswindell committed
347
					SAFEPRINTF3(str2,text[RegardingByOn], msghdr_field(&msg, msg.subj), msghdr_field(&msg, msg.from, tmp)
348
						,timestr(msg.hdr.when_written.time));
349
350
351

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
352
					replied=netmail(str,msg.subj,WM_NONE, &smb, &msg);
rswindell's avatar
rswindell committed
353
					SAFEPRINTF(str2,text[DeleteMailQ],msghdr_field(&msg, msg.from)); 
354
				}
355
356
				else {
					if(!msg.from_net.type && !stricmp(str,msg.from))
357
						replied=email(msg.idx.from,str2,msg.subj,WM_NONE, &smb, &msg);
358
					else if(!stricmp(str,"SYSOP"))
359
						replied=email(1,str2,msg.subj,WM_NONE, &smb, &msg);
360
					else if((i=finduser(str))!=0)
361
						replied=email(i,str2,msg.subj,WM_NONE, &smb, &msg);
362
363
					else
						replied=false;
rswindell's avatar
rswindell committed
364
					SAFEPRINTF(str2,text[DeleteMailQ],msghdr_field(&msg, msg.from)); 
365
				}
366
367
368
369
370
371

				if(replied==true && !(msg.hdr.attr&MSG_REPLIED)) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=0;
372
					if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
373
						if(loadmsg(&msg,msg.idx.number) >= 0) {
374
375
376
							msg.hdr.attr|=MSG_REPLIED;
							msg.idx.attr=msg.hdr.attr;
							if((i=smb_putmsg(&smb,&msg))!=0)
377
								errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
378
379
380
381
							smb_unlockmsghdr(&smb,&msg); 
						}
						smb_unlocksmbhdr(&smb);
					}
382
383
				}

384
				if(msg.hdr.attr&MSG_DELETE || noyes(str2)) {
385
					if(smb.curmsg<smb.msgs-1) smb.curmsg++;
386
387
388
389
390
					else done=1;
					break;	}
				/* Case 'D': must follow! */
			case 'D':   /* Delete last piece (toggle) */
				if(msg.hdr.attr&MSG_PERMANENT) {
391
					bprintf(text[CantDeleteMsg], smb.curmsg + 1);
392
					domsg=0;
393
394
					break; 
				}
395
396
397
398
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
399
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
400
					if(loadmsg(&msg,msg.idx.number) >= 0) {
401
402
403
404
						msg.hdr.attr^=MSG_DELETE;
						msg.idx.attr=msg.hdr.attr;
		//				  mail[smb.curmsg].attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
405
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
406
407
408
409
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
410
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
411
412
				else done=1;
				break;
413
414
415
			case 'K':	/* Kill All Mail */
				SAFEPRINTF(str,text[DeleteMailQ],"everyone");
				if(!noyes(str))
416
					delallmail(usernumber, which, /* permanent: */false, lm_mode);
417
418
				domsg=false;
				break;
419
420
421
			case 'F':  /* Forward last piece */
				domsg=0;
				bputs(text[ForwardMailTo]);
422
				if(!getstr(str, sizeof(str) - 1, K_TRIM))
423
					break;
424
425
				smb_getmsgidx(&smb,&msg);
				if(!forwardmail(&msg, str))
426
427
					break;
				domsg=1;
428
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
429
				else done=1;
430
				if(msg.hdr.attr&(MSG_PERMANENT | MSG_DELETE))
431
					break;
rswindell's avatar
rswindell committed
432
				SAFEPRINTF(str2,text[DeleteMailQ],msghdr_field(&msg, msg.from));
433
434
				if(!yesno(str2))
					break;
435
				smb_freemsgmem(&msg);
436
				msg.idx.offset=0;
437
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
438
					if(loadmsg(&msg,msg.idx.number) >= 0) {
439
440
441
442
						msg.hdr.attr|=MSG_DELETE;
						msg.idx.attr=msg.hdr.attr;
		//				  mail[smb.curmsg].attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
443
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
444
445
446
447
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
448
449
				break;
			case 'H':
450
				domsg=0;
451
				dump_msghdr(&msg);
452
453
454
				break;
			case 'L':     /* List mail */
				domsg=0;
455
456
457
458
459
460
461
462
				if(cfg.listmsgs_mod[0]) {
					char cmdline[256];

					safe_snprintf(cmdline, sizeof(cmdline), "%s %s %d %u %lu", cfg.listmsgs_mod, "mail", which, usernumber, lm_mode);
					exec_bin(cmdline, &main_csi);
					break;
				}

463
464
				bprintf(text[StartWithN],(long)smb.curmsg+1);
				if((i=getnum(smb.msgs))>0)
465
466
467
468
					i--;
				else if(i==-1)
					break;
				else
469
					i=smb.curmsg;
470
				if(which==MAIL_SENT)
471
					bprintf(text[MailSentLstHdr], order);
472
				else if(which==MAIL_ALL)
473
					bprintf(text[MailOnSystemLstHdr], order);
474
				else
475
					bprintf(text[MailWaitingLstHdr], order);
deuce's avatar
deuce committed
476
				for(u=i;u<smb.msgs && !msgabort();u++) {
477
478
479
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
480
					msg.idx.offset=mail[u].offset;
481
					if(loadmsg(&msg,mail[u].number) < 0)
482
483
484
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
rswindell's avatar
rswindell committed
485
486
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailOnSystemLstFmt)
487
							,u+1,msg.from,msg.to
488
							,mail_listing_flag(&msg)
489
490
							,msg.subj);
					else
rswindell's avatar
rswindell committed
491
492
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailWaitingLstFmt),u+1
493
494
495
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
496
							,mail_listing_flag(&msg)
497
498
							,msg.subj);
					smb_freemsgmem(&msg);
499
500
					msg.total_hfields=0; 
				}
501
502
503
504
505
				break;
			case 'Q':
				done=1;
				break;
			case 'C':   /* Change attributes of last piece */
rswindell's avatar
rswindell committed
506
				i=chmsgattr(msg);
507
508
509
510
511
512
				if(msg.hdr.attr==i)
					break;
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
513
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
514
					if(loadmsg(&msg,msg.idx.number) >= 0) {
515
516
						msg.hdr.attr=msg.idx.attr=(ushort)i;
						if((i=smb_putmsg(&smb,&msg))!=0)
517
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
518
519
520
521
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
522
523
				break;
			case '>':
524
525
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].subj==msg.idx.subj)
526
						break;
527
528
				if(u<smb.msgs)
					smb.curmsg=u;
529
				else {
530
					domsg=0;
531
532
					bputs(text[NoMessagesFound]);
				}
533
534
				break;
			case '<':   /* Search Title backward */
535
				for(i=smb.curmsg-1;i>-1;i--)
536
537
538
					if(mail[i].subj==msg.idx.subj)
						break;
				if(i>-1)
539
					smb.curmsg=i;
540
				else {
541
					domsg=0;
542
543
					bputs(text[NoMessagesFound]);
				}
544
				break;
545
			case ')':
546
547
			case '}':   /* Search Author forward */
				strcpy(str,msg.from);
548
549
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].from==msg.idx.from)
550
						break;
551
552
				if(u<smb.msgs)
					smb.curmsg=u;
553
				else {
554
					domsg=0;
555
556
					bputs(text[NoMessagesFound]);
				}
557
558
				break;
			case 'N':   /* Got to next un-read message */
559
560
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(!(mail[u].attr&MSG_READ))
561
						break;
562
563
				if(u<smb.msgs)
					smb.curmsg=u;
564
				else {
565
					domsg=0;
566
567
					bputs(text[NoMessagesFound]);
				}
568
				break;
569
			case '(':
570
571
			case '{':   /* Search Author backward */
				strcpy(str,msg.from);
572
573
574
575
576
577
578
579
				if(smb.curmsg > 0) {
					for(u=smb.curmsg-1;;u--) {
						if(mail[u].from==msg.idx.from) {
							smb.curmsg=u;
							break;
						}
						if(u==0) {
							domsg=0;
580
							bputs(text[NoMessagesFound]);
581
582
583
584
							break;
						}
					}
				}
585
586
587
				break;
			case ']':   /* Search To User forward */
				strcpy(str,msg.to);
588
589
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].to==msg.idx.to)
590
						break;
591
592
				if(u<smb.msgs)
					smb.curmsg=u;
593
				else {
594
					domsg=0;
595
596
					bputs(text[NoMessagesFound]);
				}
597
598
599
				break;
			case '[':   /* Search To User backward */
				strcpy(str,msg.to);
600
601
602
603
604
605
606
607
				if(smb.curmsg > 0) {
					for(u=smb.curmsg-1;;u--) {
						if(mail[u].to==msg.idx.to) {
							smb.curmsg=u;
							break;
						}
						if(u==0) {
							domsg=0;
608
							bputs(text[NoMessagesFound]);
609
610
611
612
							break;
						}
					}
				}
613
				break;
614
615
616
617
618
619
620
621
622
623
			case TERM_KEY_HOME:
				smb.curmsg = 0;
				newline();
				break;
			case TERM_KEY_END:
				smb.curmsg = smb.msgs - 1;
				newline();
				break;
			case TERM_KEY_RIGHT:
				newline();
624
625
			case 0:
			case '+':
626
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
627
628
				else done=1;
				break;
629
630
			case TERM_KEY_LEFT:
				newline();
631
			case '-':
632
				if(smb.curmsg>0) smb.curmsg--;
633
634
635
636
637
638
639
640
				break;
			case 'S':
				domsg=0;
	/*
				if(!yesno(text[SaveMsgToFile]))
					break;
	*/
				bputs(text[FileToWriteTo]);
641
				if(getstr(str,50,K_LINE))
rswindell's avatar
rswindell committed
642
					msgtotxt(&smb, &msg, str, /* header: */true, /* mode: */GETMSGTXT_ALL);
643
644
645
646
647
648
				break;
			case 'E':
				editmsg(&msg,INVALID_SUB);
				break;
			case 'T':
				domsg=0;
649
650
651
652
653
				u=smb.curmsg;
				if(u) u++;
				v=u+10;
				if(v>smb.msgs)
					v=smb.msgs;
654
655

				if(which==MAIL_SENT)
656
					bprintf(text[MailSentLstHdr], order);
657
				else if(which==MAIL_ALL)
658
					bprintf(text[MailOnSystemLstHdr], order);
659
				else
660
					bprintf(text[MailWaitingLstHdr], order);
661
				for(;u<v;u++) {
662
663
664
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
665
					msg.idx.offset=mail[u].offset;
666
					if(loadmsg(&msg,mail[u].number) < 0)
667
668
669
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
rswindell's avatar
rswindell committed
670
671
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailOnSystemLstFmt)
672
							,u+1,msg.from,msg.to
673
							,mail_listing_flag(&msg)
674
675
							,msg.subj);
					else
rswindell's avatar
rswindell committed
676
677
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailWaitingLstFmt),u+1
678
679
680
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
681
							,mail_listing_flag(&msg)
682
683
							,msg.subj);
					smb_freemsgmem(&msg);
684
685
					msg.total_hfields=0; 
				}
686
				smb.curmsg=(u-1);
687
				break;
688
			case 'U':   /* user edit */
689
690
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
691
692
693
694
695
				unum = msg.idx.from;
				if(unum == 0)
					unum = matchuser(&cfg, msg.from, /*sysop_alias: */FALSE);
				if(unum == 0 && which != MAIL_YOUR)
					unum = msg.idx.to;
696
				if(unum == 0 || unum > lastuser(&cfg)) {
697
698
699
					bputs(text[UnknownUser]);
					domsg=false;
				} else
700
					useredit(unum);
701
				break;
702
#if 0
703
704
705
706
			case 'U':	/* View Unread-Only (toggle) */
			{
				domsg = false;
				if(!(lm_mode&LM_UNREAD)) {
707
708
					if(getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */0)
						== getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */MSG_READ)) {
709
						bprintf(text[NoMailWaiting], "un-read mail");
710
711
712
713
						break;
					}
				}
				lm_mode ^= LM_UNREAD;
714
715
716
				bprintf("%s: %s"
					,text[DisplayUnreadMessagesOnlyQ]
					,(lm_mode&LM_UNREAD) ? text[On] : text[Off]);
717
718
719
				CRLF;
				break;
			}
720
#endif
721
722
723
			case 'V':	/* View SPAM (toggle) */
			{
				domsg = false;
724
				int spam = getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */MSG_SPAM);
725
726
727
728
				if(!spam) {
					bprintf(text[NoMailWaiting], "SPAM");
					break;
				}
729
				if(spam >= getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */0)) {
730
731
732
					bprintf(text[NoMailWaiting], "HAM");
					break;
				}
733
				bputs(text[SPAMVisibilityIsNow]);
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
				switch(lm_mode&(LM_SPAMONLY | LM_NOSPAM)) {
					case 0:
						lm_mode |= LM_NOSPAM;
						bputs(text[Off]);
						break;
					case LM_NOSPAM:
						lm_mode ^= (LM_SPAMONLY | LM_NOSPAM);
						bputs(text[Only]);
						break;
					case LM_SPAMONLY:
						lm_mode &= ~LM_SPAMONLY;
						bputs(text[On]);
						break;
				}
				CRLF;
				break;
			}
751
			case 'P':   /* Purge author and all mail to/from */
752
				if(noyes(text[UeditDeleteQ]))
753
754
755
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
756
757
758
759
760
761
762
				if((which==MAIL_SENT ? msg.idx.to : msg.idx.from) == 0) {
					bputs(text[UnknownUser]);
					domsg=false;
				} else {
					purgeuser(msg.idx.from);
					if(smb.curmsg<smb.msgs-1) smb.curmsg++;
				}
763
				break;
764
765
766
767
768
769
770
771
			case '/':
				domsg = false;
				int64_t i64;
				if((i64=get_start_msgnum(&smb))<0)
					break;
				bputs(text[SearchStringPrompt]);
				if(!getstr(search_str,40,K_LINE|K_UPPER|K_EDIT|K_AUTODEL))
					break;
772
				searchmail(mail, (long)i64, smb.msgs, which, search_str, order);
773
				break;
774
			case '?':
rswindell's avatar
rswindell committed
775
				menu(menu_file);
776
				if(SYSOP && which==MAIL_SENT)
777
					menu("syssmail");
778
				else if(SYSOP && which==MAIL_YOUR)
779
					menu("sysmailr");   /* Sysop Mail Read */
780
781
				domsg=0;
				break;
782
783
784
				
		} 
	}
785
786
787
788

	if(msg.total_hfields)
		smb_freemsgmem(&msg);

789
	if(smb.msgs)
deuce's avatar
deuce committed
790
		free(mail);
791
792
793
794
795
796
797

	/***************************************/
	/* Delete messages marked for deletion */
	/***************************************/

	if(cfg.sys_misc&SM_DELEMAIL) {
		if((i=smb_locksmbhdr(&smb))!=0) 			/* Lock the base, so nobody */
798
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);	/* messes with the index */
799
		else
800
801
			delmail(usernumber,which); 
	}
802
803
804

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
805
	current_msg=NULL;
806
807
}

808
long sbbs_t::searchmail(mail_t *mail, long start, long msgs, int which, const char *search, const char* order)
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
{
	char*	buf;
	char	subj[128];
	long	l,found=0;
	smbmsg_t msg;

	msg.total_hfields=0;
	for(l=start;l<msgs && !msgabort();l++) {
		msg.idx.offset=mail[l].offset;
		if(loadmsg(&msg,mail[l].number) < 0)
			continue;
		smb_unlockmsghdr(&smb,&msg);
		buf=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL);
		if(!buf) {
			smb_freemsgmem(&msg);
			continue; 
		}
		strupr(buf);
		strip_ctrl(buf, buf);
		SAFECOPY(subj,msg.subj);
		strupr(subj);
		if(strstr(buf,search) || strstr(subj,search)) {
			if(!found) {
				if(which==MAIL_SENT)
833
					bprintf(text[MailSentLstHdr], order);
834
				else if(which==MAIL_ALL)
835
					bprintf(text[MailOnSystemLstHdr], order);
836
				else
837
					bprintf(text[MailWaitingLstHdr], order);
838
839
			}
			if(which==MAIL_ALL)
rswindell's avatar
rswindell committed
840
841
				bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
					,msghdr_text(&msg, MailOnSystemLstFmt)
842
843
844
845
					,l+1,msg.from,msg.to
					,mail_listing_flag(&msg)
					,msg.subj);
			else
rswindell's avatar
rswindell committed
846
847
				bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
					,msghdr_text(&msg, MailWaitingLstFmt),l+1
848
849
850
851
852
853
854
855
856
857
858
859
860
					,which==MAIL_SENT ? msg.to
					: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
					? text[Anonymous] : msg.from
					,mail_listing_flag(&msg)
					,msg.subj);
			found++; 
		}
		free(buf);
		smb_freemsgmem(&msg); 
	}

	return(found);
}