readmail.cpp 25.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* readmail.cpp */

/* Synchronet private mail reading function */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
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
 *																			*
 * 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										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"

40
41
42
static char mail_listing_flag(smbmsg_t* msg)
{
	if(msg->hdr.attr&MSG_DELETE)				return '-';
43
	if(msg->hdr.attr&MSG_SPAM)					return 'S';
44
45
46
47
48
49
50
51
52
53
54
	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 '*';
}

55
56
57
/****************************************************************************/
/* Reads mail waiting for usernumber.                                       */
/****************************************************************************/
rswindell's avatar
rswindell committed
58
void sbbs_t::readmail(uint usernumber, int which, long lm_mode)
59
60
{
	char	str[256],str2[256],str3[256],done=0,domsg=1
61
			,*p,*tp,*sp,ch;
62
	char	path[MAX_PATH+1];
63
	char 	tmp[512];
64
65
	int		i;
	uint32_t u,v;
rswindell's avatar
rswindell committed
66
	int		error;
67
	int		mismatches=0,act;
68
	uint	unum;
rswindell's avatar
rswindell committed
69
    long    length,l,last_mode;
70
71
72
73
74
	ulong	last;
	bool	replied;
	file_t	fd;
	mail_t	*mail;
	smbmsg_t msg;
75
	char search_str[128] = "";
76

77
78
79
80
	if(cfg.readmail_mod[0] && !readmail_inside) {
		char cmdline[256];

		readmail_inside = true;
rswindell's avatar
rswindell committed
81
		safe_snprintf(cmdline, sizeof(cmdline), "%s %d %u %lu", cfg.readmail_mod, which, usernumber, lm_mode);
82
83
84
85
86
		exec_bin(cmdline, &main_csi);
		readmail_inside = false;
		return;
	}

87
88
89
90
91
	if(which==MAIL_SENT && useron.rest&FLAG('K')) {
		bputs(text[R_ReadSentMail]);
		return;
	}

92
93
94
95
96
97
	msg.total_hfields=0;			/* init to NULL, cause not allocated yet */

	fd.dir=cfg.total_dirs+1;			/* temp dir for file attachments */

	if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
		errormsg(WHERE,ERR_OPEN,"MAIL",i);
98
99
		return; 
	}
100
	sprintf(smb.file,"%smail",cfg.data_dir);
101
	smb.retry_time=cfg.smb_retry_time;
102
	smb.subnum=INVALID_SUB;
103
104
105
	if((i=smb_open(&smb))!=0) {
		smb_stack(&smb,SMB_STACK_POP);
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
106
107
		return; 
	}
108
109

	if(cfg.sys_misc&SM_SYSVDELM && (SYSOP || cfg.sys_misc&SM_USRVDELM))
rswindell's avatar
rswindell committed
110
		lm_mode |= LM_INCDEL;
111
	mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
112
	last_mode = lm_mode;
113
	if(!smb.msgs) {
114
115
116
117
118
		if(which==MAIL_SENT)
			bputs(text[NoMailSent]);
		else if(which==MAIL_ALL)
			bputs(text[NoMailOnSystem]);
		else
rswindell's avatar
rswindell committed
119
			bprintf(text[NoMailWaiting], lm_mode&LM_UNREAD ? "un-read mail" : "mail");
120
121
		smb_close(&smb);
		smb_stack(&smb,SMB_STACK_POP);
122
123
		return; 
	}
124
125
126
127
128
129
130
131
132
133

	last=smb.status.last_msg;

	if(which==MAIL_SENT)
		act=NODE_RSML;
	else if(which==MAIL_ALL)
		act=NODE_SYSP;
	else
		act=NODE_RMAL;
	action=act;
134
	if(smb.msgs>1 && which!=MAIL_ALL) {
135
136
137
138
139
		if(which==MAIL_SENT)
			bputs(text[MailSentLstHdr]);
		else
			bputs(text[MailWaitingLstHdr]);

140
		for(smb.curmsg=0;smb.curmsg<smb.msgs && !msgabort();smb.curmsg++) {
141
142
143
			if(msg.total_hfields)
				smb_freemsgmem(&msg);
			msg.total_hfields=0;
144
			msg.idx.offset=mail[smb.curmsg].offset;
145
			if(loadmsg(&msg,mail[smb.curmsg].number) < 1)
146
147
				continue;
			smb_unlockmsghdr(&smb,&msg);
148
			bprintf(text[MailWaitingLstFmt],smb.curmsg+1
149
150
151
				,which==MAIL_SENT ? msg.to
				: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP ? text[Anonymous]
				: msg.from
152
				,mail_listing_flag(&msg)
153
154
				,msg.subj);
			smb_freemsgmem(&msg);
155
156
			msg.total_hfields=0; 
		}
157
158

		ASYNC;
159
160
161
162
		if(sys_status&SS_ABORT) {
			domsg=0;
			smb.curmsg=0;
		} else {
163
			bprintf(text[StartWithN],1L);
164
165
166
167
			l=getnum(smb.msgs);
			if(l>0)
				smb.curmsg=l-1;
			else if(l==-1) {
deuce's avatar
deuce committed
168
				free(mail);
169
170
				smb_close(&smb);
				smb_stack(&smb,SMB_STACK_POP);
171
				return;
172
			}
173
174
			else
				smb.curmsg=l;
175
176
177
		}
		sys_status&=~SS_ABORT; 
	}
178
	else {
179
		smb.curmsg=0;
180
		if(which==MAIL_ALL)
181
182
			domsg=0; 
	}
183
	if(which==MAIL_SENT) {
184
		logline("E","read sent mail");
185
	} else if(which==MAIL_ALL) {
186
		logline("S+","read all mail");
187
	} else {
188
		logline("E","read mail");
189
	}
rswindell's avatar
rswindell committed
190
191
192
	const char* menu_file = (which == MAIL_ALL ? "allmail" : which==MAIL_SENT ? "sentmail" : "mailread");
	if(useron.misc&RIP)
		menu(menu_file); 
193
	current_msg=&msg;	/* For MSG_* @-codes and bbs.msg_* property values */
194
195
196
197
198
199
200
	while(online && !done) {
		action=act;

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

201
202
203
204
205
		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;
206
207

		if((i=smb_locksmbhdr(&smb))!=0) {
208
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);
209
210
			break; 
		}
211
212
213

		if((i=smb_getstatus(&smb))!=0) {
			smb_unlocksmbhdr(&smb);
214
			errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
215
216
			break; 
		}
217
218
		smb_unlocksmbhdr(&smb);

219
		if(smb.status.last_msg!=last || lm_mode != last_mode) { 	/* New messages */
220
			last=smb.status.last_msg;
deuce's avatar
deuce committed
221
			free(mail);
222
223
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);   /* So re-load */
			if(!smb.msgs)
224
				break;
225
226
227
228
229
230
231
232
233
			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);
			}
234
			last_mode = lm_mode;
235
236
			continue; 
		}
237

238
		if(loadmsg(&msg,mail[smb.curmsg].number) < 0) {	/* Message header gone */
239
			if(mismatches>5) {	/* We can't do this too many times in a row */
240
				errormsg(WHERE,ERR_CHK,"message number",mail[smb.curmsg].number);
241
242
				break; 
			}
deuce's avatar
deuce committed
243
			free(mail);
244
245
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
			if(!smb.msgs)
246
				break;
247
			last_mode = lm_mode;
248
249
			if(smb.curmsg>(smb.msgs-1))
				smb.curmsg=(smb.msgs-1);
250
			mismatches++;
251
252
			continue; 
		}
253
254
255
256
257
258
259
260
261
262
263
		smb_unlockmsghdr(&smb,&msg);
		msg.idx.attr=msg.hdr.attr;

		mismatches=0;

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

			show_msg(&msg
				,msg.from_ext && msg.idx.from==1 && !msg.from_net.type
					? 0:P_NOATCODES);

264
			char* txt;
265
266
267
			int attachment_index = 0;
			bool found = true;
			while((txt=smb_getmsgtxt(&smb,&msg, 0)) != NULL && found) {
268
269
270
				char filename[MAX_PATH+1] = {0};
				uint32_t filelen = 0;
				uint8_t* filedata;
271
				if((filedata = smb_getattachment(&msg, txt, filename, &filelen, attachment_index++)) != NULL 
272
273
274
					&& filename[0] != 0 && filelen > 0) {
					char tmp[32];
					sprintf(str3, text[DownloadAttachedFileQ], filename, ultoac(filelen,tmp));
275
					if(!noyes(str3)) {
276
277
278
279
280
281
282
283
284
285
286
287
288
289
						char fpath[MAX_PATH+1];
						SAFEPRINTF2(fpath, "%s%s", cfg.temp_dir, filename);
						FILE* fp = fopen(fpath, "wb");
						if(fp == NULL)
							errormsg(WHERE, ERR_OPEN, fpath, 0);
						else {
							int result = fwrite(filedata, filelen, 1, fp);
							fclose(fp);
							if(!result)
								errormsg(WHERE, ERR_WRITE, fpath, filelen);
							else
								sendfile(fpath, useron.prot, "attachment");
						}
					}
290
291
				} else
					found = false;
292
293
294
				smb_freemsgtxt(txt);
			}

295
296
			if(msg.hdr.auxattr&MSG_FILEATTACH) {  /* Attached file */
				smb_getmsgidx(&smb,&msg);
297
				SAFECOPY(str, msg.subj);					/* filenames (multiple?) in title */
298
299
				tp=str;
				while(online) {
300
					p=strchr(tp,' ');
301
302
303
304
305
					if(p) *p=0;
					sp=strrchr(tp,'/');              /* sp is slash pointer */
					if(!sp) sp=strrchr(tp,'\\');
					if(sp) tp=sp+1;
					padfname(tp,fd.name);
306
					SAFEPRINTF3(path,"%sfile/%04u.in/%s"  /* path is path/fname */
307
						,cfg.data_dir,msg.idx.to,tp);
rswindell's avatar
rswindell committed
308
309
310
					if(!fexistcase(path) && msg.idx.from)
						SAFEPRINTF3(path,"%sfile/%04u.out/%s"  /* path is path/fname */
							,cfg.data_dir,msg.idx.from,tp);
311
					length=(long)flength(path);
312
					if(length<1)
313
						bprintf(text[FileDoesNotExist], tp);
314
315
316
317
318
319
					else if(!(useron.exempt&FLAG('T')) && cur_cps && !SYSOP
						&& length/(long)cur_cps>(time_t)timeleft)
						bputs(text[NotEnoughTimeToDl]);
					else {
						sprintf(str3,text[DownloadAttachedFileQ]
							,tp,ultoac(length,tmp));
320
						if(length>0L && text[DownloadAttachedFileQ][0] && yesno(str3)) {
rswindell's avatar
rswindell committed
321
							{	/* Remote User */
322
								xfer_prot_menu(XFER_DOWNLOAD);
323
324
325
326
								mnemonics(text[ProtocolOrQuit]);
								strcpy(str3,"Q");
								for(i=0;i<cfg.total_prots;i++)
									if(cfg.prot[i]->dlcmd[0]
rswindell's avatar
rswindell committed
327
										&& chk_ar(cfg.prot[i]->ar,&useron,&client)) {
328
										sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
329
330
										strcat(str3,tmp); 
									}
331
332
333
								ch=(char)getkeys(str3,0);
								for(i=0;i<cfg.total_prots;i++)
									if(cfg.prot[i]->dlcmd[0] && ch==cfg.prot[i]->mnemonic
rswindell's avatar
rswindell committed
334
										&& chk_ar(cfg.prot[i]->ar,&useron,&client))
335
336
										break;
								if(i<cfg.total_prots) {
337
									error=protocol(cfg.prot[i],XFER_DOWNLOAD,path,nulstr,false);
338
339
									if(checkprotresult(cfg.prot[i],error,&fd)) {
										if(which==MAIL_YOUR)
340
											remove(path);
341
342
343
344
345
346
347
348
349
										logon_dlb+=length;	/* Update stats */
										logon_dls++;
										useron.dls=(ushort)adjustuserrec(&cfg,useron.number
											,U_DLS,5,1);
										useron.dlb=adjustuserrec(&cfg,useron.number
											,U_DLB,10,length);
										bprintf(text[FileNBytesSent]
											,fd.name,ultoac(length,tmp));
										sprintf(str3
350
											,"downloaded attached file: %s"
351
352
353
354
355
356
357
358
359
360
361
											,fd.name);
										logline("D-",str3); 
									}
									autohangup(); 
								} 
							} 
						} 
					}
					if(!p)
						break;
					tp=p+1;
362
					while(*tp==' ') tp++; 
363
				}
364
				sprintf(str,"%sfile/%04u.in",cfg.data_dir,usernumber);
365
366
				rmdir(str); 
			}
367
			if(which==MAIL_YOUR && !(msg.hdr.attr&MSG_READ)) {
368
				mail[smb.curmsg].attr|=MSG_READ;
369
370
371
372
373
374
				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 */
375
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
376
					if(loadmsg(&msg,msg.idx.number) >= 0) {
377
						msg.hdr.attr|=MSG_READ;
378
379
						if(msg.hdr.attr&MSG_KILLREAD)
							msg.hdr.attr|=MSG_DELETE;
380
381
						msg.idx.attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
382
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
383
384
385
386
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb); 
				}
387
388
				if(!msg.total_hfields) {				/* unsuccessful reload */
					domsg=0;
389
390
					continue; 
				}
391
			}
392
		}
393
394
		else domsg=1;

rswindell's avatar
rswindell committed
395
396
		if(useron.misc&WIP)
			menu(menu_file); 
397
398
399

		ASYNC;
		if(which==MAIL_SENT)
400
			bprintf(text[ReadingSentMail],smb.curmsg+1,smb.msgs);
401
		else if(which==MAIL_ALL)
402
			bprintf(text[ReadingAllMail],smb.curmsg+1,smb.msgs);
403
		else
404
			bprintf(text[ReadingMail],smb.curmsg+1,smb.msgs);
405
		sprintf(str,"ADFLNQRT?<>[]{}()-+/!");
406
		if(SYSOP)
407
			strcat(str,"CUSPH");
408
409
410
411
412
413
		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
414
		l=getkeys(str,smb.msgs);
415
416
417
		if(l&0x80000000L) {
			if(l==-1)	/* ctrl-c */
				break;
418
			smb.curmsg=(l&~0x80000000L)-1;
419
420
			continue; 
		}
421
		switch(l) {
422
423
424
425
			case '!':
				lm_mode ^= LM_REVERSE;
				domsg=0;
				break;
426
427
428
429
430
431
432
			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;
433
434
				if((msg.hdr.attr&(MSG_NOREPLY|MSG_ANONYMOUS)) && !SYSOP) {
					bputs(text[CantReplyToMsg]);
435
436
					break; 
				}
437

438
				quotemsg(&msg,/* include tails: */TRUE);
439

440
				if(msg.from_net.addr==NULL)
441
					SAFECOPY(str,msg.from);
442
				else if(msg.from_net.type==NET_FIDO) 	/* FidoNet type */
443
					SAFEPRINTF2(str,"%s@%s",msg.from
444
						,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
445
				else if(msg.from_net.type==NET_INTERNET || strchr((char*)msg.from_net.addr,'@')!=NULL) {
446
447
448
449
450
451
452
453
					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);
454
455
456
457
458
459
460
461
462
463
464

				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 */
					sprintf(str2,text[Regarding],msg.subj);
				else						/* Reply to other */
					sprintf(str2,text[RegardingByOn],msg.subj,msg.from
465
						,timestr(msg.hdr.when_written.time));
466
467
468
469

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
					replied=netmail(str,msg.subj,WM_QUOTE);
470
471
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
472
473
474
475
476
477
478
				else {
					if(!msg.from_net.type && !stricmp(str,msg.from))
						replied=email(msg.idx.from,str2,msg.subj,WM_EMAIL|WM_QUOTE);
					else if(!stricmp(str,"SYSOP"))
						replied=email(1,str2,msg.subj,WM_EMAIL|WM_QUOTE);
					else if((i=finduser(str))!=0)
						replied=email(i,str2,msg.subj,WM_EMAIL|WM_QUOTE);
479
480
					else
						replied=false;
481
482
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
483
484
485
486
487
488

				if(replied==true && !(msg.hdr.attr&MSG_REPLIED)) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=0;
489
					if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
490
						if(loadmsg(&msg,msg.idx.number) >= 0) {
491
492
493
							msg.hdr.attr|=MSG_REPLIED;
							msg.idx.attr=msg.hdr.attr;
							if((i=smb_putmsg(&smb,&msg))!=0)
494
								errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
495
496
497
498
							smb_unlockmsghdr(&smb,&msg); 
						}
						smb_unlocksmbhdr(&smb);
					}
499
500
				}

501
				if(msg.hdr.attr&MSG_DELETE || noyes(str2)) {
502
					if(smb.curmsg<smb.msgs-1) smb.curmsg++;
503
504
505
506
507
					else done=1;
					break;	}
				/* Case 'D': must follow! */
			case 'D':   /* Delete last piece (toggle) */
				if(msg.hdr.attr&MSG_PERMANENT) {
508
					bputs(text[CantDeleteMsg]);
509
					domsg=0;
510
511
					break; 
				}
512
513
514
515
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
516
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
517
					if(loadmsg(&msg,msg.idx.number) >= 0) {
518
519
520
521
						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)
522
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
523
524
525
526
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
527
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
528
529
				else done=1;
				break;
530
531
532
			case 'K':	/* Kill All Mail */
				SAFEPRINTF(str,text[DeleteMailQ],"everyone");
				if(!noyes(str))
533
					delallmail(usernumber, which, /* permanent: */false, lm_mode);
534
535
				domsg=false;
				break;
536
537
538
			case 'F':  /* Forward last piece */
				domsg=0;
				bputs(text[ForwardMailTo]);
539
				if(!getstr(str,LEN_ALIAS,cfg.uq&UQ_NOUPRLWR ? K_NONE:K_UPRLWR))
540
541
542
543
544
					break;
				i=finduser(str);
				if(!i)
					break;
				domsg=1;
545
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
546
547
548
549
550
551
552
553
554
555
556
557
				else done=1;
				smb_getmsgidx(&smb,&msg);
				forwardmail(&msg,i);
				if(msg.hdr.attr&MSG_PERMANENT)
					break;
				sprintf(str2,text[DeleteMailQ],msg.from);
				if(!yesno(str2))
					break;
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
558
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
559
					if(loadmsg(&msg,msg.idx.number) >= 0) {
560
561
562
563
						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)
564
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
565
566
567
568
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
569

570
571
				break;
			case 'H':
572
				domsg=0;
573
				msghdr(&msg);
574
575
576
				break;
			case 'L':     /* List mail */
				domsg=0;
577
578
				bprintf(text[StartWithN],(long)smb.curmsg+1);
				if((i=getnum(smb.msgs))>0)
579
580
581
582
					i--;
				else if(i==-1)
					break;
				else
583
					i=smb.curmsg;
584
585
586
587
588
589
				if(which==MAIL_SENT)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
deuce's avatar
deuce committed
590
				for(u=i;u<smb.msgs && !msgabort();u++) {
591
592
593
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
594
					msg.idx.offset=mail[u].offset;
595
					if(loadmsg(&msg,mail[u].number) < 0)
596
597
598
599
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
						bprintf(text[MailOnSystemLstFmt]
600
							,u+1,msg.from,msg.to
601
							,mail_listing_flag(&msg)
602
603
							,msg.subj);
					else
604
						bprintf(text[MailWaitingLstFmt],u+1
605
606
607
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
608
							,mail_listing_flag(&msg)
609
610
							,msg.subj);
					smb_freemsgmem(&msg);
611
612
					msg.total_hfields=0; 
				}
613
614
615
616
617
				break;
			case 'Q':
				done=1;
				break;
			case 'C':   /* Change attributes of last piece */
rswindell's avatar
rswindell committed
618
				i=chmsgattr(msg);
619
620
621
622
623
624
				if(msg.hdr.attr==i)
					break;
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
625
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
626
					if(loadmsg(&msg,msg.idx.number) >= 0) {
627
628
						msg.hdr.attr=msg.idx.attr=(ushort)i;
						if((i=smb_putmsg(&smb,&msg))!=0)
629
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
630
631
632
633
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
634
635
				break;
			case '>':
636
637
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].subj==msg.idx.subj)
638
						break;
639
640
				if(u<smb.msgs)
					smb.curmsg=u;
641
				else {
642
					domsg=0;
643
644
					bputs(text[NoMessagesFound]);
				}
645
646
				break;
			case '<':   /* Search Title backward */
647
				for(i=smb.curmsg-1;i>-1;i--)
648
649
650
					if(mail[i].subj==msg.idx.subj)
						break;
				if(i>-1)
651
					smb.curmsg=i;
652
				else {
653
					domsg=0;
654
655
					bputs(text[NoMessagesFound]);
				}
656
				break;
657
			case ')':
658
659
			case '}':   /* Search Author forward */
				strcpy(str,msg.from);
660
661
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].from==msg.idx.from)
662
						break;
663
664
				if(u<smb.msgs)
					smb.curmsg=u;
665
				else {
666
					domsg=0;
667
668
					bputs(text[NoMessagesFound]);
				}
669
670
				break;
			case 'N':   /* Got to next un-read message */
671
672
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(!(mail[u].attr&MSG_READ))
673
						break;
674
675
				if(u<smb.msgs)
					smb.curmsg=u;
676
				else {
677
					domsg=0;
678
679
					bputs(text[NoMessagesFound]);
				}
680
				break;
681
			case '(':
682
683
			case '{':   /* Search Author backward */
				strcpy(str,msg.from);
684
685
686
687
688
689
690
691
				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;
692
							bputs(text[NoMessagesFound]);
693
694
695
696
							break;
						}
					}
				}
697
698
699
				break;
			case ']':   /* Search To User forward */
				strcpy(str,msg.to);
700
701
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].to==msg.idx.to)
702
						break;
703
704
				if(u<smb.msgs)
					smb.curmsg=u;
705
				else {
706
					domsg=0;
707
708
					bputs(text[NoMessagesFound]);
				}
709
710
711
				break;
			case '[':   /* Search To User backward */
				strcpy(str,msg.to);
712
713
714
715
716
717
718
719
				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;
720
							bputs(text[NoMessagesFound]);
721
722
723
724
							break;
						}
					}
				}
725
726
727
				break;
			case 0:
			case '+':
728
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
729
730
731
				else done=1;
				break;
			case '-':
732
				if(smb.curmsg>0) smb.curmsg--;
733
734
735
736
737
738
739
740
				break;
			case 'S':
				domsg=0;
	/*
				if(!yesno(text[SaveMsgToFile]))
					break;
	*/
				bputs(text[FileToWriteTo]);
741
742
				if(getstr(str,50,K_LINE))
					msgtotxt(&msg,str, /* header: */true, /* mode: */GETMSGTXT_ALL);
743
744
745
746
747
748
				break;
			case 'E':
				editmsg(&msg,INVALID_SUB);
				break;
			case 'T':
				domsg=0;
749
750
751
752
753
				u=smb.curmsg;
				if(u) u++;
				v=u+10;
				if(v>smb.msgs)
					v=smb.msgs;
754
755
756
757
758
759
760

				if(which==MAIL_SENT)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
761
				for(;u<v;u++) {
762
763
764
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
765
					msg.idx.offset=mail[u].offset;
766
					if(loadmsg(&msg,mail[u].number) < 0)
767
768
769
770
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
						bprintf(text[MailOnSystemLstFmt]
771
							,u+1,msg.from,msg.to
772
							,mail_listing_flag(&msg)
773
774
							,msg.subj);
					else
775
						bprintf(text[MailWaitingLstFmt],u+1
776
777
778
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
779
							,mail_listing_flag(&msg)
780
781
							,msg.subj);
					smb_freemsgmem(&msg);
782
783
					msg.total_hfields=0; 
				}
784
				smb.curmsg=(u-1);
785
				break;
786
			case 'U':   /* user edit */
787
788
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
789
790
791
792
793
				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;
794
				if(unum == 0 || unum > lastuser(&cfg)) {
795
796
797
					bputs(text[UnknownUser]);
					domsg=false;
				} else
798
					useredit(unum);
799
				break;
800
#if 0
801
802
803
804
			case 'U':	/* View Unread-Only (toggle) */
			{
				domsg = false;
				if(!(lm_mode&LM_UNREAD)) {
805
806
					if(getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */0)
						== getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */MSG_READ)) {
807
						bprintf(text[NoMailWaiting], "un-read mail");
808
809
810
811
						break;
					}
				}
				lm_mode ^= LM_UNREAD;
812
813
814
				bprintf("%s: %s"
					,text[DisplayUnreadMessagesOnlyQ]
					,(lm_mode&LM_UNREAD) ? text[On] : text[Off]);
815
816
817
				CRLF;
				break;
			}
818
#endif
819
820
821
			case 'V':	/* View SPAM (toggle) */
			{
				domsg = false;
822
				int spam = getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */MSG_SPAM);
823
824
825
826
				if(!spam) {
					bprintf(text[NoMailWaiting], "SPAM");
					break;
				}
827
				if(spam >= getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */0)) {
828
829
830
					bprintf(text[NoMailWaiting], "HAM");
					break;
				}
831
				bputs(text[SPAMVisibilityIsNow]);
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
				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;
			}
849
			case 'P':   /* Purge author and all mail to/from */
850
				if(noyes(text[UeditDeleteQ]))
851
852
853
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
854
855
856
857
858
859
860
				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++;
				}
861
				break;
862
863
864
865
866
867
868
869
870
871
			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;
				searchmail(mail, (long)i64, smb.msgs, which, search_str);
				break;
872
			case '?':
rswindell's avatar
rswindell committed
873
				menu(menu_file);
874
				if(SYSOP && which==MAIL_SENT)
875
					menu("syssmail");
876
				else if(SYSOP && which==MAIL_YOUR)
877
					menu("sysmailr");   /* Sysop Mail Read */
878
879
				domsg=0;
				break;
880
881
882
				
		} 
	}
883
884
885
886

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

887
	if(smb.msgs)
deuce's avatar
deuce committed
888
		free(mail);
889
890
891
892
893
894
895

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

	if(cfg.sys_misc&SM_DELEMAIL) {
		if((i=smb_locksmbhdr(&smb))!=0) 			/* Lock the base, so nobody */
896
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);	/* messes with the index */
897
		else
898
899
			delmail(usernumber,which); 
	}
900
901
902

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
903
	current_msg=NULL;
904
905
}

906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
long sbbs_t::searchmail(mail_t *mail, long start, long msgs, int which, const char *search)
{
	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)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
			}
			if(which==MAIL_ALL)
				bprintf(text[MailOnSystemLstFmt]
					,l+1,msg.from,msg.to
					,mail_listing_flag(&msg)
					,msg.subj);
			else
				bprintf(text[MailWaitingLstFmt],l+1
					,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);
}