readmail.cpp 24.2 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
58
59
60
/****************************************************************************/
/* Reads mail waiting for usernumber.                                       */
/****************************************************************************/
void sbbs_t::readmail(uint usernumber, int which)
{
	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;
69
    long    length,l,lm_mode, 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
81
82
83
84
85
86
	if(cfg.readmail_mod[0] && !readmail_inside) {
		char cmdline[256];

		readmail_inside = true;
		safe_snprintf(cmdline, sizeof(cmdline), "%s %d %u", cfg.readmail_mod, which, usernumber);
		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
110
111
112

	if(cfg.sys_misc&SM_SYSVDELM && (SYSOP || cfg.sys_misc&SM_USRVDELM))
		lm_mode=LM_INCDEL;
	else
		lm_mode=0;
113
	mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
114
	last_mode = lm_mode;
115
	if(!smb.msgs) {
116
117
118
119
120
		if(which==MAIL_SENT)
			bputs(text[NoMailSent]);
		else if(which==MAIL_ALL)
			bputs(text[NoMailOnSystem]);
		else
121
			bprintf(text[NoMailWaiting], "mail");
122
123
		smb_close(&smb);
		smb_stack(&smb,SMB_STACK_POP);
124
125
		return; 
	}
126
127
128
129
130
131
132
133
134
135

	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;
136
	if(smb.msgs>1 && which!=MAIL_ALL) {
137
138
139
140
141
		if(which==MAIL_SENT)
			bputs(text[MailSentLstHdr]);
		else
			bputs(text[MailWaitingLstHdr]);

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

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

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

208
209
210
211
212
		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;
213
214

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

		if((i=smb_getstatus(&smb))!=0) {
			smb_unlocksmbhdr(&smb);
221
			errormsg(WHERE,ERR_READ,smb.file,i,smb.last_error);
222
223
			break; 
		}
224
225
		smb_unlocksmbhdr(&smb);

226
		if(smb.status.last_msg!=last || lm_mode != last_mode) { 	/* New messages */
227
			last=smb.status.last_msg;
deuce's avatar
deuce committed
228
			free(mail);
229
230
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);   /* So re-load */
			if(!smb.msgs)
231
				break;
232
			last_mode = lm_mode;
233
234
			for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
				if(mail[smb.curmsg].number==msg.idx.number)
235
					break;
236
237
			if(smb.curmsg>=smb.msgs)
				smb.curmsg=(smb.msgs-1);
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
267
268
		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);

			if(msg.hdr.auxattr&MSG_FILEATTACH) {  /* Attached file */
				smb_getmsgidx(&smb,&msg);
269
				SAFECOPY(str, msg.subj);					/* filenames (multiple?) in title */
270
271
				tp=str;
				while(online) {
272
					p=strchr(tp,' ');
273
274
275
276
277
					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);
278
					SAFEPRINTF3(path,"%sfile/%04u.in/%s"  /* path is path/fname */
279
						,cfg.data_dir,msg.idx.to,tp);
280
					length=(long)flength(path);
281
					if(length<1)
282
						bprintf(text[FileDoesNotExist], tp);
283
284
285
286
287
288
					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));
289
						if(length>0L && text[DownloadAttachedFileQ][0] && yesno(str3)) {
rswindell's avatar
rswindell committed
290
							{	/* Remote User */
291
								xfer_prot_menu(XFER_DOWNLOAD);
292
293
294
295
								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
296
										&& chk_ar(cfg.prot[i]->ar,&useron,&client)) {
297
										sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
298
299
										strcat(str3,tmp); 
									}
300
301
302
								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
303
										&& chk_ar(cfg.prot[i]->ar,&useron,&client))
304
305
										break;
								if(i<cfg.total_prots) {
306
									error=protocol(cfg.prot[i],XFER_DOWNLOAD,path,nulstr,false);
307
308
									if(checkprotresult(cfg.prot[i],error,&fd)) {
										if(which==MAIL_YOUR)
309
											remove(path);
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
										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;
332
					while(*tp==' ') tp++; 
333
				}
334
				sprintf(str,"%sfile/%04u.in",cfg.data_dir,usernumber);
335
336
				rmdir(str); 
			}
337
			if(which==MAIL_YOUR && !(msg.hdr.attr&MSG_READ)) {
338
				mail[smb.curmsg].attr|=MSG_READ;
339
340
341
342
343
344
				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 */
345
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
346
					if(loadmsg(&msg,msg.idx.number) >= 0) {
347
						msg.hdr.attr|=MSG_READ;
348
349
						if(msg.hdr.attr&MSG_KILLREAD)
							msg.hdr.attr|=MSG_DELETE;
350
351
						msg.idx.attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
352
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
353
354
355
356
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb); 
				}
357
358
				if(!msg.total_hfields) {				/* unsuccessful reload */
					domsg=0;
359
360
					continue; 
				}
361
			}
362
		}
363
364
365
		else domsg=1;

		if(useron.misc&WIP) {
366
367
			strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL ?
				"allmail" : "sentmail");
368
369
			menu(str); 
		}
370
371
372

		ASYNC;
		if(which==MAIL_SENT)
373
			bprintf(text[ReadingSentMail],smb.curmsg+1,smb.msgs);
374
		else if(which==MAIL_ALL)
375
			bprintf(text[ReadingAllMail],smb.curmsg+1,smb.msgs);
376
		else
377
			bprintf(text[ReadingMail],smb.curmsg+1,smb.msgs);
378
		sprintf(str,"ADFLNQRT?<>[]{}-+/");
379
		if(SYSOP)
380
			strcat(str,"CUSPH");
381
382
383
384
385
386
		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
387
		l=getkeys(str,smb.msgs);
388
389
390
		if(l&0x80000000L) {
			if(l==-1)	/* ctrl-c */
				break;
391
			smb.curmsg=(l&~0x80000000L)-1;
392
393
			continue; 
		}
394
395
396
397
398
399
400
401
		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;
402
403
				if((msg.hdr.attr&(MSG_NOREPLY|MSG_ANONYMOUS)) && !SYSOP) {
					bputs(text[CantReplyToMsg]);
404
405
					break; 
				}
406

407
				quotemsg(&msg,/* include tails: */TRUE);
408

409
				if(msg.from_net.addr==NULL)
410
					SAFECOPY(str,msg.from);
411
				else if(msg.from_net.type==NET_FIDO) 	/* FidoNet type */
412
					SAFEPRINTF2(str,"%s@%s",msg.from
413
						,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
414
				else if(msg.from_net.type==NET_INTERNET || strchr((char*)msg.from_net.addr,'@')!=NULL) {
415
416
417
418
419
420
421
422
					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);
423
424
425
426
427
428
429
430
431
432
433

				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
434
						,timestr(msg.hdr.when_written.time));
435
436
437
438

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
					replied=netmail(str,msg.subj,WM_QUOTE);
439
440
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
441
442
443
444
445
446
447
				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);
448
449
					else
						replied=false;
450
451
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
452
453
454
455
456
457

				if(replied==true && !(msg.hdr.attr&MSG_REPLIED)) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=0;
458
					if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
459
						if(loadmsg(&msg,msg.idx.number) >= 0) {
460
461
462
							msg.hdr.attr|=MSG_REPLIED;
							msg.idx.attr=msg.hdr.attr;
							if((i=smb_putmsg(&smb,&msg))!=0)
463
								errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
464
465
466
467
							smb_unlockmsghdr(&smb,&msg); 
						}
						smb_unlocksmbhdr(&smb);
					}
468
469
				}

470
				if(msg.hdr.attr&MSG_DELETE || noyes(str2)) {
471
					if(smb.curmsg<smb.msgs-1) smb.curmsg++;
472
473
474
475
476
					else done=1;
					break;	}
				/* Case 'D': must follow! */
			case 'D':   /* Delete last piece (toggle) */
				if(msg.hdr.attr&MSG_PERMANENT) {
477
					bputs(text[CantDeleteMsg]);
478
					domsg=0;
479
480
					break; 
				}
481
482
483
484
				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
490
						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)
491
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
492
493
494
495
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
496
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
497
498
				else done=1;
				break;
499
500
501
			case 'K':	/* Kill All Mail */
				SAFEPRINTF(str,text[DeleteMailQ],"everyone");
				if(!noyes(str))
502
					delallmail(usernumber, which, /* permanent: */false, lm_mode);
503
504
				domsg=false;
				break;
505
506
507
			case 'F':  /* Forward last piece */
				domsg=0;
				bputs(text[ForwardMailTo]);
508
				if(!getstr(str,LEN_ALIAS,cfg.uq&UQ_NOUPRLWR ? K_NONE:K_UPRLWR))
509
510
511
512
513
					break;
				i=finduser(str);
				if(!i)
					break;
				domsg=1;
514
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
515
516
517
518
519
520
521
522
523
524
525
526
				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;
527
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
528
					if(loadmsg(&msg,msg.idx.number) >= 0) {
529
530
531
532
						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)
533
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
534
535
536
537
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
538

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

				if(which==MAIL_SENT)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
728
				for(;u<v;u++) {
729
730
731
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
732
					msg.idx.offset=mail[u].offset;
733
					if(loadmsg(&msg,mail[u].number) < 0)
734
735
736
737
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
						bprintf(text[MailOnSystemLstFmt]
738
							,u+1,msg.from,msg.to
739
							,mail_listing_flag(&msg)
740
741
							,msg.subj);
					else
742
						bprintf(text[MailWaitingLstFmt],u+1
743
744
745
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
746
							,mail_listing_flag(&msg)
747
748
							,msg.subj);
					smb_freemsgmem(&msg);
749
750
					msg.total_hfields=0; 
				}
751
				smb.curmsg=(u-1);
752
753
754
755
				break;
			case 'U':   /* user edit */
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
756
757
758
				if((unum=(which==MAIL_SENT ? msg.idx.to : msg.idx.from)) == 0)
					unum=(which==MAIL_SENT ? msg.idx.from : msg.idx.to);
				if(unum == 0 || unum > lastuser(&cfg)) {
759
760
761
					bputs(text[UnknownUser]);
					domsg=false;
				} else
762
					useredit(unum);
763
				break;
764
765
766
			case 'V':	/* View SPAM (toggle) */
			{
				domsg = false;
767
				int spam = getmail(&cfg, usernumber, /* Sent: */FALSE, /* SPAM-ONLY */TRUE);
768
769
770
771
				if(!spam) {
					bprintf(text[NoMailWaiting], "SPAM");
					break;
				}
772
				if(spam >= getmail(&cfg, usernumber, /* Sent: */FALSE, /* SPAM-ONLY */FALSE)) {
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
					bprintf(text[NoMailWaiting], "HAM");
					break;
				}
				bprintf(text[SPAMVisibilityIsNow]);
				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;
			}
794
			case 'P':   /* Purge author and all mail to/from */
795
				if(noyes(text[UeditDeleteQ]))
796
797
798
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
799
800
801
802
803
804
805
				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++;
				}
806
				break;
807
808
809
810
811
812
813
814
815
816
			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;
817
			case '?':
818
819
				strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL
						? "allmail" : "sentmail");
820
821
				menu(str);
				if(SYSOP && which==MAIL_SENT)
822
					menu("syssmail");
823
				else if(SYSOP && which==MAIL_YOUR)
824
					menu("sysmailr");   /* Sysop Mail Read */
825
826
				domsg=0;
				break;
827
828
829
				
		} 
	}
830
831
832
833

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

834
	if(smb.msgs)
deuce's avatar
deuce committed
835
		free(mail);
836
837
838
839
840
841
842

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

	if(cfg.sys_misc&SM_DELEMAIL) {
		if((i=smb_locksmbhdr(&smb))!=0) 			/* Lock the base, so nobody */
843
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);	/* messes with the index */
844
		else
845
846
			delmail(usernumber,which); 
	}
847
848
849

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
850
	current_msg=NULL;
851
852
}

853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
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);
}