readmail.cpp 25.9 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
	const char* order = (lm_mode&LM_REVERSE) ? "newest" : "oldest";
135
	if(smb.msgs>1 && which!=MAIL_ALL) {
136
		if(which==MAIL_SENT)
137
			bprintf(text[MailSentLstHdr], order);
138
		else
139
			bprintf(text[MailWaitingLstHdr], order);
140

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

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

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

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

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

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

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

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

		mismatches=0;

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

rswindell's avatar
rswindell committed
262
			show_msg(&smb, &msg
263
264
265
				,msg.from_ext && msg.idx.from==1 && !msg.from_net.type
					? 0:P_NOATCODES);

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

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

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

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

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
469
					replied=netmail(str,msg.subj,WM_NONE, &smb, &msg);
470
471
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
472
473
				else {
					if(!msg.from_net.type && !stricmp(str,msg.from))
474
						replied=email(msg.idx.from,str2,msg.subj,WM_NONE, &smb, &msg);
475
					else if(!stricmp(str,"SYSOP"))
476
						replied=email(1,str2,msg.subj,WM_NONE, &smb, &msg);
477
					else if((i=finduser(str))!=0)
478
						replied=email(i,str2,msg.subj,WM_NONE, &smb, &msg);
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
					bprintf(text[CantDeleteMsg], smb.curmsg + 1);
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
				if(which==MAIL_SENT)
585
					bprintf(text[MailSentLstHdr], order);
586
				else if(which==MAIL_ALL)
587
					bprintf(text[MailOnSystemLstHdr], order);
588
				else
589
					bprintf(text[MailWaitingLstHdr], order);
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
				if(getstr(str,50,K_LINE))
rswindell's avatar
rswindell committed
742
					msgtotxt(&smb, &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

				if(which==MAIL_SENT)
756
					bprintf(text[MailSentLstHdr], order);
757
				else if(which==MAIL_ALL)
758
					bprintf(text[MailOnSystemLstHdr], order);
759
				else
760
					bprintf(text[MailWaitingLstHdr], order);
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
			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;
870
				searchmail(mail, (long)i64, smb.msgs, which, search_str, order);
871
				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
long sbbs_t::searchmail(mail_t *mail, long start, long msgs, int which, const char *search, const char* order)
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
{
	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)
931
					bprintf(text[MailSentLstHdr], order);
932
				else if(which==MAIL_ALL)
933
					bprintf(text[MailOnSystemLstHdr], order);
934
				else
935
					bprintf(text[MailWaitingLstHdr], order);
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
			}
			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);
}