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
184
185
186
187
188
189
190
191
192
	if(which==MAIL_SENT) {
		sprintf(str,"%s read sent mail",useron.alias);
		logline("E",str);
	} else if(which==MAIL_ALL) {
		sprintf(str,"%s read all mail",useron.alias);
		logline("S+",str);
	} else {
		sprintf(str,"%s read mail",useron.alias);
		logline("E",str);
	}
rswindell's avatar
rswindell committed
193
194
195
	const char* menu_file = (which == MAIL_ALL ? "allmail" : which==MAIL_SENT ? "sentmail" : "mailread");
	if(useron.misc&RIP)
		menu(menu_file); 
196
	current_msg=&msg;	/* For MSG_* @-codes and bbs.msg_* property values */
197
198
199
200
201
202
203
	while(online && !done) {
		action=act;

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

204
205
206
207
208
		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;
209
210

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

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

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

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

267
			char* txt;
268
269
270
			int attachment_index = 0;
			bool found = true;
			while((txt=smb_getmsgtxt(&smb,&msg, 0)) != NULL && found) {
271
272
273
				char filename[MAX_PATH+1] = {0};
				uint32_t filelen = 0;
				uint8_t* filedata;
274
				if((filedata = smb_getattachment(&msg, txt, filename, &filelen, attachment_index++)) != NULL 
275
276
277
					&& filename[0] != 0 && filelen > 0) {
					char tmp[32];
					sprintf(str3, text[DownloadAttachedFileQ], filename, ultoac(filelen,tmp));
278
					if(!noyes(str3)) {
279
280
281
282
283
284
285
286
287
288
289
290
291
292
						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");
						}
					}
293
294
				} else
					found = false;
295
296
297
				smb_freemsgtxt(txt);
			}

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

rswindell's avatar
rswindell committed
399
400
		if(useron.misc&WIP)
			menu(menu_file); 
401
402
403

		ASYNC;
		if(which==MAIL_SENT)
404
			bprintf(text[ReadingSentMail],smb.curmsg+1,smb.msgs);
405
		else if(which==MAIL_ALL)
406
			bprintf(text[ReadingAllMail],smb.curmsg+1,smb.msgs);
407
		else
408
			bprintf(text[ReadingMail],smb.curmsg+1,smb.msgs);
409
		sprintf(str,"ADFLNQRT?<>[]{}-+/");
410
		if(SYSOP)
411
			strcat(str,"CUSPH");
412
413
414
415
416
417
		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
418
		l=getkeys(str,smb.msgs);
419
420
421
		if(l&0x80000000L) {
			if(l==-1)	/* ctrl-c */
				break;
422
			smb.curmsg=(l&~0x80000000L)-1;
423
424
			continue; 
		}
425
426
427
428
429
430
431
432
		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;
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
657
658
				break;
			case '}':   /* Search Author forward */
				strcpy(str,msg.from);
659
660
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].from==msg.idx.from)
661
						break;
662
663
				if(u<smb.msgs)
					smb.curmsg=u;
664
				else {
665
					domsg=0;
666
667
					bputs(text[NoMessagesFound]);
				}
668
669
				break;
			case 'N':   /* Got to next un-read message */
670
671
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(!(mail[u].attr&MSG_READ))
672
						break;
673
674
				if(u<smb.msgs)
					smb.curmsg=u;
675
				else {
676
					domsg=0;
677
678
					bputs(text[NoMessagesFound]);
				}
679
680
681
				break;
			case '{':   /* Search Author backward */
				strcpy(str,msg.from);
682
683
684
685
686
687
688
689
				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;
690
							bputs(text[NoMessagesFound]);
691
692
693
694
							break;
						}
					}
				}
695
696
697
				break;
			case ']':   /* Search To User forward */
				strcpy(str,msg.to);
698
699
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].to==msg.idx.to)
700
						break;
701
702
				if(u<smb.msgs)
					smb.curmsg=u;
703
				else {
704
					domsg=0;
705
706
					bputs(text[NoMessagesFound]);
				}
707
708
709
				break;
			case '[':   /* Search To User backward */
				strcpy(str,msg.to);
710
711
712
713
714
715
716
717
				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;
718
							bputs(text[NoMessagesFound]);
719
720
721
722
							break;
						}
					}
				}
723
724
725
				break;
			case 0:
			case '+':
726
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
727
728
729
				else done=1;
				break;
			case '-':
730
				if(smb.curmsg>0) smb.curmsg--;
731
732
733
734
735
736
737
738
				break;
			case 'S':
				domsg=0;
	/*
				if(!yesno(text[SaveMsgToFile]))
					break;
	*/
				bputs(text[FileToWriteTo]);
739
740
				if(getstr(str,50,K_LINE))
					msgtotxt(&msg,str, /* header: */true, /* mode: */GETMSGTXT_ALL);
741
742
743
744
745
746
				break;
			case 'E':
				editmsg(&msg,INVALID_SUB);
				break;
			case 'T':
				domsg=0;
747
748
749
750
751
				u=smb.curmsg;
				if(u) u++;
				v=u+10;
				if(v>smb.msgs)
					v=smb.msgs;
752
753
754
755
756
757
758

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

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

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

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

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

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
901
	current_msg=NULL;
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
953
954
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);
}