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
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
233
234
235
236
237
238
239
240
			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);
			}
241
			last_mode = lm_mode;
242
243
			continue; 
		}
244

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

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

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

		if(useron.misc&WIP) {
401
402
			strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL ?
				"allmail" : "sentmail");
403
404
			menu(str); 
		}
405
406
407

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

442
				quotemsg(&msg,/* include tails: */TRUE);
443

444
				if(msg.from_net.addr==NULL)
445
					SAFECOPY(str,msg.from);
446
				else if(msg.from_net.type==NET_FIDO) 	/* FidoNet type */
447
					SAFEPRINTF2(str,"%s@%s",msg.from
448
						,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
449
				else if(msg.from_net.type==NET_INTERNET || strchr((char*)msg.from_net.addr,'@')!=NULL) {
450
451
452
453
454
455
456
457
					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);
458
459
460
461
462
463
464
465
466
467
468

				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
469
						,timestr(msg.hdr.when_written.time));
470
471
472
473

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
					replied=netmail(str,msg.subj,WM_QUOTE);
474
475
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
476
477
478
479
480
481
482
				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);
483
484
					else
						replied=false;
485
486
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
487
488
489
490
491
492

				if(replied==true && !(msg.hdr.attr&MSG_REPLIED)) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=0;
493
					if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
494
						if(loadmsg(&msg,msg.idx.number) >= 0) {
495
496
497
							msg.hdr.attr|=MSG_REPLIED;
							msg.idx.attr=msg.hdr.attr;
							if((i=smb_putmsg(&smb,&msg))!=0)
498
								errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
499
500
501
502
							smb_unlockmsghdr(&smb,&msg); 
						}
						smb_unlocksmbhdr(&smb);
					}
503
504
				}

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

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

				if(which==MAIL_SENT)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
763
				for(;u<v;u++) {
764
765
766
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
767
					msg.idx.offset=mail[u].offset;
768
					if(loadmsg(&msg,mail[u].number) < 0)
769
770
771
772
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
						bprintf(text[MailOnSystemLstFmt]
773
							,u+1,msg.from,msg.to
774
							,mail_listing_flag(&msg)
775
776
							,msg.subj);
					else
777
						bprintf(text[MailWaitingLstFmt],u+1
778
779
780
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
781
							,mail_listing_flag(&msg)
782
783
							,msg.subj);
					smb_freemsgmem(&msg);
784
785
					msg.total_hfields=0; 
				}
786
				smb.curmsg=(u-1);
787
				break;
788
			case '!':   /* user edit */
789
790
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
791
792
793
				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)) {
794
795
796
					bputs(text[UnknownUser]);
					domsg=false;
				} else
797
					useredit(unum);
798
				break;
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
806
807
808
809
810
811
812
813
814
						bprintf(text[NoMailWaiting], "Un-read");
						break;
					}
				}
				lm_mode ^= LM_UNREAD;
				bputs(text[DisplayUnreadMessagesOnlyQ]);
				bputs((lm_mode&LM_UNREAD) ? text[On] : text[Off]);
				CRLF;
				break;
			}
815
816
817
			case 'V':	/* View SPAM (toggle) */
			{
				domsg = false;
818
				int spam = getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */MSG_SPAM);
819
820
821
822
				if(!spam) {
					bprintf(text[NoMailWaiting], "SPAM");
					break;
				}
823
				if(spam >= getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */0)) {
824
825
826
					bprintf(text[NoMailWaiting], "HAM");
					break;
				}
827
				bputs(text[SPAMVisibilityIsNow]);
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
				switch(lm_mode&(LM_SPAMONLY | LM_NOSPAM)) {
					case 0:
						lm_mode |= LM_NOSPAM;
						bputs(text[Off]);
						break;
					case LM_NOSPAM:
						lm_mode ^= (LM_SPAMONLY | LM_NOSPAM);
						bputs(text[Only]);
						break;
					case LM_SPAMONLY:
						lm_mode &= ~LM_SPAMONLY;
						bputs(text[On]);
						break;
				}
				CRLF;
				break;
			}
845
			case 'P':   /* Purge author and all mail to/from */
846
				if(noyes(text[UeditDeleteQ]))
847
848
849
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
850
851
852
853
854
855
856
				if((which==MAIL_SENT ? msg.idx.to : msg.idx.from) == 0) {
					bputs(text[UnknownUser]);
					domsg=false;
				} else {
					purgeuser(msg.idx.from);
					if(smb.curmsg<smb.msgs-1) smb.curmsg++;
				}
857
				break;
858
859
860
861
862
863
864
865
866
867
			case '/':
				domsg = false;
				int64_t i64;
				if((i64=get_start_msgnum(&smb))<0)
					break;
				bputs(text[SearchStringPrompt]);
				if(!getstr(search_str,40,K_LINE|K_UPPER|K_EDIT|K_AUTODEL))
					break;
				searchmail(mail, (long)i64, smb.msgs, which, search_str);
				break;
868
			case '?':
869
870
				strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL
						? "allmail" : "sentmail");
871
872
				menu(str);
				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);
}