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
653
654
				break;
			case '}':   /* Search Author forward */
				strcpy(str,msg.from);
655
656
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].from==msg.idx.from)
657
						break;
658
659
				if(u<smb.msgs)
					smb.curmsg=u;
660
				else {
661
					domsg=0;
662
663
					bputs(text[NoMessagesFound]);
				}
664
665
				break;
			case 'N':   /* Got to next un-read message */
666
667
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(!(mail[u].attr&MSG_READ))
668
						break;
669
670
				if(u<smb.msgs)
					smb.curmsg=u;
671
				else {
672
					domsg=0;
673
674
					bputs(text[NoMessagesFound]);
				}
675
676
677
				break;
			case '{':   /* Search Author backward */
				strcpy(str,msg.from);
678
679
680
681
682
683
684
685
				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;
686
							bputs(text[NoMessagesFound]);
687
688
689
690
							break;
						}
					}
				}
691
692
693
				break;
			case ']':   /* Search To User forward */
				strcpy(str,msg.to);
694
695
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].to==msg.idx.to)
696
						break;
697
698
				if(u<smb.msgs)
					smb.curmsg=u;
699
				else {
700
					domsg=0;
701
702
					bputs(text[NoMessagesFound]);
				}
703
704
705
				break;
			case '[':   /* Search To User backward */
				strcpy(str,msg.to);
706
707
708
709
710
711
712
713
				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;
714
							bputs(text[NoMessagesFound]);
715
716
717
718
							break;
						}
					}
				}
719
720
721
				break;
			case 0:
			case '+':
722
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
723
724
725
				else done=1;
				break;
			case '-':
726
				if(smb.curmsg>0) smb.curmsg--;
727
728
729
730
731
732
733
734
				break;
			case 'S':
				domsg=0;
	/*
				if(!yesno(text[SaveMsgToFile]))
					break;
	*/
				bputs(text[FileToWriteTo]);
735
736
				if(getstr(str,50,K_LINE))
					msgtotxt(&msg,str, /* header: */true, /* mode: */GETMSGTXT_ALL);
737
738
739
740
741
742
				break;
			case 'E':
				editmsg(&msg,INVALID_SUB);
				break;
			case 'T':
				domsg=0;
743
744
745
746
747
				u=smb.curmsg;
				if(u) u++;
				v=u+10;
				if(v>smb.msgs)
					v=smb.msgs;
748
749
750
751
752
753
754

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

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

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

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

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

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
897
	current_msg=NULL;
898
899
}

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