readmail.cpp 25.6 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
422
423
424
425
426
427
428
		switch(l) {
			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;
429
430
				if((msg.hdr.attr&(MSG_NOREPLY|MSG_ANONYMOUS)) && !SYSOP) {
					bputs(text[CantReplyToMsg]);
431
432
					break; 
				}
433

434
				quotemsg(&msg,/* include tails: */TRUE);
435

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

				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
461
						,timestr(msg.hdr.when_written.time));
462
463
464
465

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
					replied=netmail(str,msg.subj,WM_QUOTE);
466
467
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
468
469
470
471
472
473
474
				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);
475
476
					else
						replied=false;
477
478
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
479
480
481
482
483
484

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

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

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

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

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

883
	if(smb.msgs)
deuce's avatar
deuce committed
884
		free(mail);
885
886
887
888
889
890
891

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

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

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
899
	current_msg=NULL;
900
901
}

902
903
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
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);
}