readmail.cpp 23.8 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 61
	char	str[256],str2[256],done=0,domsg=1
			,*p;
62
	char 	tmp[512];
63 64
	int		i;
	uint32_t u,v;
65
	int		mismatches=0,act;
66
	uint	unum;
67
    long    l,last_mode;
68 69 70 71
	ulong	last;
	bool	replied;
	mail_t	*mail;
	smbmsg_t msg;
72
	char search_str[128] = "";
73

74 75 76 77 78 79 80 81
	if(which==MAIL_SENT)
		act=NODE_RSML;
	else if(which==MAIL_ALL)
		act=NODE_SYSP;
	else
		act=NODE_RMAL;
	action=act;

82 83 84 85
	if(cfg.readmail_mod[0] && !readmail_inside) {
		char cmdline[256];

		readmail_inside = true;
rswindell's avatar
rswindell committed
86
		safe_snprintf(cmdline, sizeof(cmdline), "%s %d %u %lu", cfg.readmail_mod, which, usernumber, lm_mode);
87 88 89 90 91
		exec_bin(cmdline, &main_csi);
		readmail_inside = false;
		return;
	}

92 93 94 95 96
	if(which==MAIL_SENT && useron.rest&FLAG('K')) {
		bputs(text[R_ReadSentMail]);
		return;
	}

97 98 99 100
	msg.total_hfields=0;			/* init to NULL, cause not allocated yet */

	if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
		errormsg(WHERE,ERR_OPEN,"MAIL",i);
101 102
		return; 
	}
103
	SAFEPRINTF(smb.file,"%smail",cfg.data_dir);
104
	smb.retry_time=cfg.smb_retry_time;
105
	smb.subnum=INVALID_SUB;
106 107 108
	if((i=smb_open(&smb))!=0) {
		smb_stack(&smb,SMB_STACK_POP);
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
109 110
		return; 
	}
111 112

	if(cfg.sys_misc&SM_SYSVDELM && (SYSOP || cfg.sys_misc&SM_USRVDELM))
rswindell's avatar
rswindell committed
113
		lm_mode |= LM_INCDEL;
114
	mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
115
	last_mode = lm_mode;
116
	if(!smb.msgs) {
117 118 119 120 121
		if(which==MAIL_SENT)
			bputs(text[NoMailSent]);
		else if(which==MAIL_ALL)
			bputs(text[NoMailOnSystem]);
		else
rswindell's avatar
rswindell committed
122
			bprintf(text[NoMailWaiting], lm_mode&LM_UNREAD ? "un-read mail" : "mail");
123 124
		smb_close(&smb);
		smb_stack(&smb,SMB_STACK_POP);
125 126
		return; 
	}
127 128 129

	last=smb.status.last_msg;

130
	const char* order = (lm_mode&LM_REVERSE) ? "newest" : "oldest";
131
	if(smb.msgs>1 && which!=MAIL_ALL) {
132
		if(which==MAIL_SENT)
133
			bprintf(text[MailSentLstHdr], order);
134
		else
135
			bprintf(text[MailWaitingLstHdr], order);
136

137
		for(smb.curmsg=0;smb.curmsg<smb.msgs && !msgabort();smb.curmsg++) {
138 139 140
			if(msg.total_hfields)
				smb_freemsgmem(&msg);
			msg.total_hfields=0;
141
			msg.idx.offset=mail[smb.curmsg].offset;
142
			if(loadmsg(&msg,mail[smb.curmsg].number) < 1)
143 144
				continue;
			smb_unlockmsghdr(&smb,&msg);
rswindell's avatar
rswindell committed
145 146
			bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
				,msghdr_text(&msg, MailWaitingLstFmt), smb.curmsg+1
147 148 149
				,which==MAIL_SENT ? msg.to
				: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP ? text[Anonymous]
				: msg.from
150
				,mail_listing_flag(&msg)
151 152
				,msg.subj);
			smb_freemsgmem(&msg);
153 154
			msg.total_hfields=0; 
		}
155 156

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

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

199 200 201 202 203
		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;
204 205

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

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

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

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

		mismatches=0;

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

259
			if(!show_msg(&smb, &msg
260
				,msg.from_ext && msg.idx.from==1 && !msg.from_net.type
261 262
					? 0:P_NOATCODES))
				errormsg(WHERE,"showing", "mail message", msg.hdr.number, smb.last_error);
263
			download_msg_attachments(&smb, &msg, which == MAIL_YOUR);
264
			if(which==MAIL_YOUR && !(msg.hdr.attr&MSG_READ)) {
265
				mail[smb.curmsg].attr|=MSG_READ;
266 267 268 269 270 271
				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 */
272
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
273
					if(loadmsg(&msg,msg.idx.number) >= 0) {
274
						msg.hdr.attr|=MSG_READ;
275 276
						if(msg.hdr.attr&MSG_KILLREAD)
							msg.hdr.attr|=MSG_DELETE;
277 278
						msg.idx.attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
279
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
280 281 282 283
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb); 
				}
284 285
				if(!msg.total_hfields) {				/* unsuccessful reload */
					domsg=0;
286 287
					continue; 
				}
288
			}
289
		}
290 291
		else domsg=1;

rswindell's avatar
rswindell committed
292 293
		if(useron.misc&WIP)
			menu(menu_file); 
294 295 296

		ASYNC;
		if(which==MAIL_SENT)
297
			bprintf(text[ReadingSentMail],smb.curmsg+1,smb.msgs);
298
		else if(which==MAIL_ALL)
299
			bprintf(text[ReadingAllMail],smb.curmsg+1,smb.msgs);
300
		else
301
			bprintf(text[ReadingMail],smb.curmsg+1,smb.msgs);
302 303 304 305 306
		sprintf(str,"ADFLNQRT?<>[]{}()-+/!%c%c%c%c"
			,TERM_KEY_LEFT
			,TERM_KEY_RIGHT
			,TERM_KEY_HOME
			,TERM_KEY_END);
307
		if(SYSOP)
308
			strcat(str,"CUSPH");
309 310 311 312 313 314
		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
315 316 317
		struct mouse_hotspot* hotspot_added = NULL;
		if(mouse_hotspots.first == NULL)
			hotspot_added = add_hotspot('\r');
318
		l=getkeys(str,smb.msgs);
319 320
		if(hotspot_added)
			clear_hotspots();
321 322 323
		if(l&0x80000000L) {
			if(l==-1)	/* ctrl-c */
				break;
324
			smb.curmsg=(l&~0x80000000L)-1;
325 326
			continue; 
		}
327
		switch(l) {
328 329 330 331
			case '!':
				lm_mode ^= LM_REVERSE;
				domsg=0;
				break;
332 333 334 335 336 337 338
			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;
339 340
				if((msg.hdr.attr&(MSG_NOREPLY|MSG_ANONYMOUS)) && !SYSOP) {
					bputs(text[CantReplyToMsg]);
341 342
					break; 
				}
343

344
				if(msg.from_net.addr==NULL)
345
					SAFECOPY(str,msg.from);
346
				else if(msg.from_net.type==NET_FIDO) 	/* FidoNet type */
347
					SAFEPRINTF2(str,"%s@%s",msg.from
348
						,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
349
				else if(msg.from_net.type==NET_INTERNET || strchr((char*)msg.from_net.addr,'@')!=NULL) {
350 351 352 353 354 355 356 357
					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);
358 359 360 361 362 363 364 365

				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 */
rswindell's avatar
rswindell committed
366
					SAFEPRINTF(str2,text[Regarding], msghdr_field(&msg, msg.subj));
367
				else						/* Reply to other */
rswindell's avatar
rswindell committed
368
					SAFEPRINTF3(str2,text[RegardingByOn], msghdr_field(&msg, msg.subj), msghdr_field(&msg, msg.from, tmp)
369
						,timestr(msg.hdr.when_written.time));
370 371 372

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
373
					replied=netmail(str,msg.subj,WM_NONE, &smb, &msg);
rswindell's avatar
rswindell committed
374
					SAFEPRINTF(str2,text[DeleteMailQ],msghdr_field(&msg, msg.from)); 
375
				}
376 377
				else {
					if(!msg.from_net.type && !stricmp(str,msg.from))
378
						replied=email(msg.idx.from,str2,msg.subj,WM_NONE, &smb, &msg);
379
					else if(!stricmp(str,"SYSOP"))
380
						replied=email(1,str2,msg.subj,WM_NONE, &smb, &msg);
381
					else if((i=finduser(str))!=0)
382
						replied=email(i,str2,msg.subj,WM_NONE, &smb, &msg);
383 384
					else
						replied=false;
rswindell's avatar
rswindell committed
385
					SAFEPRINTF(str2,text[DeleteMailQ],msghdr_field(&msg, msg.from)); 
386
				}
387 388 389 390 391 392

				if(replied==true && !(msg.hdr.attr&MSG_REPLIED)) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=0;
393
					if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
394
						if(loadmsg(&msg,msg.idx.number) >= 0) {
395 396 397
							msg.hdr.attr|=MSG_REPLIED;
							msg.idx.attr=msg.hdr.attr;
							if((i=smb_putmsg(&smb,&msg))!=0)
398
								errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
399 400 401 402
							smb_unlockmsghdr(&smb,&msg); 
						}
						smb_unlocksmbhdr(&smb);
					}
403 404
				}

405
				if(msg.hdr.attr&MSG_DELETE || noyes(str2)) {
406
					if(smb.curmsg<smb.msgs-1) smb.curmsg++;
407 408 409 410 411
					else done=1;
					break;	}
				/* Case 'D': must follow! */
			case 'D':   /* Delete last piece (toggle) */
				if(msg.hdr.attr&MSG_PERMANENT) {
412
					bprintf(text[CantDeleteMsg], smb.curmsg + 1);
413
					domsg=0;
414 415
					break; 
				}
416 417 418 419
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
420
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
421
					if(loadmsg(&msg,msg.idx.number) >= 0) {
422 423 424 425
						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)
426
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
427 428 429 430
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
431
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
432 433
				else done=1;
				break;
434 435 436
			case 'K':	/* Kill All Mail */
				SAFEPRINTF(str,text[DeleteMailQ],"everyone");
				if(!noyes(str))
437
					delallmail(usernumber, which, /* permanent: */false, lm_mode);
438 439
				domsg=false;
				break;
440 441 442
			case 'F':  /* Forward last piece */
				domsg=0;
				bputs(text[ForwardMailTo]);
443
				if(!getstr(str,LEN_ALIAS,cfg.uq&UQ_NOUPRLWR ? K_NONE:K_UPRLWR))
444 445 446 447 448
					break;
				i=finduser(str);
				if(!i)
					break;
				domsg=1;
449
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
450 451 452 453 454
				else done=1;
				smb_getmsgidx(&smb,&msg);
				forwardmail(&msg,i);
				if(msg.hdr.attr&MSG_PERMANENT)
					break;
rswindell's avatar
rswindell committed
455
				SAFEPRINTF(str2,text[DeleteMailQ],msghdr_field(&msg, msg.from));
456 457 458 459 460 461
				if(!yesno(str2))
					break;
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
462
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
463
					if(loadmsg(&msg,msg.idx.number) >= 0) {
464 465 466 467
						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)
468
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
469 470 471 472
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
473

474 475
				break;
			case 'H':
476
				domsg=0;
477
				dump_msghdr(&msg);
478 479 480
				break;
			case 'L':     /* List mail */
				domsg=0;
481 482 483 484 485 486 487 488
				if(cfg.listmsgs_mod[0]) {
					char cmdline[256];

					safe_snprintf(cmdline, sizeof(cmdline), "%s %s %d %u %lu", cfg.listmsgs_mod, "mail", which, usernumber, lm_mode);
					exec_bin(cmdline, &main_csi);
					break;
				}

489 490
				bprintf(text[StartWithN],(long)smb.curmsg+1);
				if((i=getnum(smb.msgs))>0)
491 492 493 494
					i--;
				else if(i==-1)
					break;
				else
495
					i=smb.curmsg;
496
				if(which==MAIL_SENT)
497
					bprintf(text[MailSentLstHdr], order);
498
				else if(which==MAIL_ALL)
499
					bprintf(text[MailOnSystemLstHdr], order);
500
				else
501
					bprintf(text[MailWaitingLstHdr], order);
deuce's avatar
deuce committed
502
				for(u=i;u<smb.msgs && !msgabort();u++) {
503 504 505
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
506
					msg.idx.offset=mail[u].offset;
507
					if(loadmsg(&msg,mail[u].number) < 0)
508 509 510
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
rswindell's avatar
rswindell committed
511 512
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailOnSystemLstFmt)
513
							,u+1,msg.from,msg.to
514
							,mail_listing_flag(&msg)
515 516
							,msg.subj);
					else
rswindell's avatar
rswindell committed
517 518
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailWaitingLstFmt),u+1
519 520 521
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
522
							,mail_listing_flag(&msg)
523 524
							,msg.subj);
					smb_freemsgmem(&msg);
525 526
					msg.total_hfields=0; 
				}
527 528 529 530 531
				break;
			case 'Q':
				done=1;
				break;
			case 'C':   /* Change attributes of last piece */
rswindell's avatar
rswindell committed
532
				i=chmsgattr(msg);
533 534 535 536 537 538
				if(msg.hdr.attr==i)
					break;
				if(msg.total_hfields)
					smb_freemsgmem(&msg);
				msg.total_hfields=0;
				msg.idx.offset=0;
539
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
540
					if(loadmsg(&msg,msg.idx.number) >= 0) {
541 542
						msg.hdr.attr=msg.idx.attr=(ushort)i;
						if((i=smb_putmsg(&smb,&msg))!=0)
543
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
544 545 546 547
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb);
				}
548 549
				break;
			case '>':
550 551
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].subj==msg.idx.subj)
552
						break;
553 554
				if(u<smb.msgs)
					smb.curmsg=u;
555
				else {
556
					domsg=0;
557 558
					bputs(text[NoMessagesFound]);
				}
559 560
				break;
			case '<':   /* Search Title backward */
561
				for(i=smb.curmsg-1;i>-1;i--)
562 563 564
					if(mail[i].subj==msg.idx.subj)
						break;
				if(i>-1)
565
					smb.curmsg=i;
566
				else {
567
					domsg=0;
568 569
					bputs(text[NoMessagesFound]);
				}
570
				break;
571
			case ')':
572 573
			case '}':   /* Search Author forward */
				strcpy(str,msg.from);
574 575
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].from==msg.idx.from)
576
						break;
577 578
				if(u<smb.msgs)
					smb.curmsg=u;
579
				else {
580
					domsg=0;
581 582
					bputs(text[NoMessagesFound]);
				}
583 584
				break;
			case 'N':   /* Got to next un-read message */
585 586
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(!(mail[u].attr&MSG_READ))
587
						break;
588 589
				if(u<smb.msgs)
					smb.curmsg=u;
590
				else {
591
					domsg=0;
592 593
					bputs(text[NoMessagesFound]);
				}
594
				break;
595
			case '(':
596 597
			case '{':   /* Search Author backward */
				strcpy(str,msg.from);
598 599 600 601 602 603 604 605
				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;
606
							bputs(text[NoMessagesFound]);
607 608 609 610
							break;
						}
					}
				}
611 612 613
				break;
			case ']':   /* Search To User forward */
				strcpy(str,msg.to);
614 615
				for(u=smb.curmsg+1;u<smb.msgs;u++)
					if(mail[u].to==msg.idx.to)
616
						break;
617 618
				if(u<smb.msgs)
					smb.curmsg=u;
619
				else {
620
					domsg=0;
621 622
					bputs(text[NoMessagesFound]);
				}
623 624 625
				break;
			case '[':   /* Search To User backward */
				strcpy(str,msg.to);
626 627 628 629 630 631 632 633
				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;
634
							bputs(text[NoMessagesFound]);
635 636 637 638
							break;
						}
					}
				}
639
				break;
640 641 642 643 644 645 646 647 648 649
			case TERM_KEY_HOME:
				smb.curmsg = 0;
				newline();
				break;
			case TERM_KEY_END:
				smb.curmsg = smb.msgs - 1;
				newline();
				break;
			case TERM_KEY_RIGHT:
				newline();
650 651
			case 0:
			case '+':
652
				if(smb.curmsg<smb.msgs-1) smb.curmsg++;
653 654
				else done=1;
				break;
655 656
			case TERM_KEY_LEFT:
				newline();
657
			case '-':
658
				if(smb.curmsg>0) smb.curmsg--;
659 660 661 662 663 664 665 666
				break;
			case 'S':
				domsg=0;
	/*
				if(!yesno(text[SaveMsgToFile]))
					break;
	*/
				bputs(text[FileToWriteTo]);
667
				if(getstr(str,50,K_LINE))
rswindell's avatar
rswindell committed
668
					msgtotxt(&smb, &msg, str, /* header: */true, /* mode: */GETMSGTXT_ALL);
669 670 671 672 673 674
				break;
			case 'E':
				editmsg(&msg,INVALID_SUB);
				break;
			case 'T':
				domsg=0;
675 676 677 678 679
				u=smb.curmsg;
				if(u) u++;
				v=u+10;
				if(v>smb.msgs)
					v=smb.msgs;
680 681

				if(which==MAIL_SENT)
682
					bprintf(text[MailSentLstHdr], order);
683
				else if(which==MAIL_ALL)
684
					bprintf(text[MailOnSystemLstHdr], order);
685
				else
686
					bprintf(text[MailWaitingLstHdr], order);
687
				for(;u<v;u++) {
688 689 690
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
691
					msg.idx.offset=mail[u].offset;
692
					if(loadmsg(&msg,mail[u].number) < 0)
693 694 695
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
rswindell's avatar
rswindell committed
696 697
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailOnSystemLstFmt)
698
							,u+1,msg.from,msg.to
699
							,mail_listing_flag(&msg)
700 701
							,msg.subj);
					else
rswindell's avatar
rswindell committed
702 703
						bprintf(P_TRUNCATE|(msg.hdr.auxattr&MSG_HFIELDS_UTF8)
							,msghdr_text(&msg, MailWaitingLstFmt),u+1
704 705 706
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
707
							,mail_listing_flag(&msg)
708 709
							,msg.subj);
					smb_freemsgmem(&msg);
710 711
					msg.total_hfields=0; 
				}
712
				smb.curmsg=(u-1);
713
				break;
714
			case 'U':   /* user edit */
715 716
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
717 718 719 720 721
				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;
722
				if(unum == 0 || unum > lastuser(&cfg)) {
723 724 725
					bputs(text[UnknownUser]);
					domsg=false;
				} else
726
					useredit(unum);
727
				break;
728
#if 0
729 730 731 732
			case 'U':	/* View Unread-Only (toggle) */
			{
				domsg = false;
				if(!(lm_mode&LM_UNREAD)) {
733 734
					if(getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */0)
						== getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */MSG_READ)) {
735
						bprintf(text[NoMailWaiting], "un-read mail");
736 737 738 739
						break;
					}
				}
				lm_mode ^= LM_UNREAD;
740 741 742
				bprintf("%s: %s"
					,text[DisplayUnreadMessagesOnlyQ]
					,(lm_mode&LM_UNREAD) ? text[On] : text[Off]);
743 744 745
				CRLF;
				break;
			}
746
#endif
747 748 749
			case 'V':	/* View SPAM (toggle) */
			{
				domsg = false;
750
				int spam = getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */MSG_SPAM);
751 752 753 754
				if(!spam) {
					bprintf(text[NoMailWaiting], "SPAM");
					break;
				}
755
				if(spam >= getmail(&cfg, usernumber, /* Sent: */FALSE, /* attr: */0)) {
756 757 758
					bprintf(text[NoMailWaiting], "HAM");
					break;
				}
759
				bputs(text[SPAMVisibilityIsNow]);
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776
				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;
			}
777
			case 'P':   /* Purge author and all mail to/from */
778
				if(noyes(text[UeditDeleteQ]))
779 780 781
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
782 783 784 785 786 787 788
				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++;
				}
789
				break;
790 791 792 793 794 795 796 797
			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;
798
				searchmail(mail, (long)i64, smb.msgs, which, search_str, order);
799
				break;
800
			case '?':
rswindell's avatar
rswindell committed
801
				menu(menu_file);
802
				if(SYSOP && which==MAIL_SENT)
803
					menu("syssmail");
804
				else if(SYSOP && which==MAIL_YOUR)
805
					menu("sysmailr");   /* Sysop Mail Read */
806 807
				domsg=0;
				break;
808 809 810
				
		} 
	}
811 812 813 814

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

815
	if(smb.msgs)
deuce's avatar
deuce committed
816
		free(mail);
817 818 819 820 821 822 823

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

	if(cfg.sys_misc&SM_DELEMAIL) {
		if((i=smb_locksmbhdr(&smb))!=0) 			/* Lock the base, so nobody */
824
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);	/* messes with the index */
825
		else
826 827
			delmail(usernumber,which); 
	}
828 829 830

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
831
	current_msg=NULL;
832 833
}

834
long sbbs_t::searchmail(mail_t *mail, long start, long msgs, int which, const char *search, const char* order)