readmail.cpp 21.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 43 44 45 46 47 48 49 50 51 52 53
static char mail_listing_flag(smbmsg_t* msg)
{
	if(msg->hdr.attr&MSG_DELETE)				return '-';
	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 '*';
}

54 55 56 57 58 59
/****************************************************************************/
/* Reads mail waiting for usernumber.                                       */
/****************************************************************************/
void sbbs_t::readmail(uint usernumber, int which)
{
	char	str[256],str2[256],str3[256],done=0,domsg=1
60
			,*p,*tp,*sp,ch;
61
	char	path[MAX_PATH+1];
62
	char 	tmp[512];
63 64
	int		i;
	uint32_t u,v;
rswindell's avatar
rswindell committed
65
	int		error;
66
	int		mismatches=0,act;
67
	uint	unum;
68 69 70 71 72 73 74
    long    length,l,lm_mode;
	ulong	last;
	bool	replied;
	file_t	fd;
	mail_t	*mail;
	smbmsg_t msg;

75 76 77 78 79 80 81 82 83 84
	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;
	}

85 86 87 88 89
	if(which==MAIL_SENT && useron.rest&FLAG('K')) {
		bputs(text[R_ReadSentMail]);
		return;
	}

90 91 92 93 94 95
	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);
96 97
		return; 
	}
98
	sprintf(smb.file,"%smail",cfg.data_dir);
99
	smb.retry_time=cfg.smb_retry_time;
100
	smb.subnum=INVALID_SUB;
101 102 103
	if((i=smb_open(&smb))!=0) {
		smb_stack(&smb,SMB_STACK_POP);
		errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
104 105
		return; 
	}
106 107 108 109 110

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

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

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

		ASYNC;
		if(!(sys_status&SS_ABORT)) {
			bprintf(text[StartWithN],1L);
160 161 162 163
			l=getnum(smb.msgs);
			if(l>0)
				smb.curmsg=l-1;
			else if(l==-1) {
deuce's avatar
deuce committed
164
				free(mail);
165 166
				smb_close(&smb);
				smb_stack(&smb,SMB_STACK_POP);
167
				return;
168
			}
169 170
			else
				smb.curmsg=l;
171 172 173
		}
		sys_status&=~SS_ABORT; 
	}
174
	else {
175
		smb.curmsg=0;
176
		if(which==MAIL_ALL)
177 178
			domsg=0; 
	}
179 180 181 182 183 184 185 186 187 188
	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);
	}
189
	if(useron.misc&RIP) {
190 191
		strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL ?
			"allmail" : "sentmail");
192 193
		menu(str); 
	}
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 220 221
		smb_unlocksmbhdr(&smb);

		if(smb.status.last_msg!=last) { 	/* New messages */
			last=smb.status.last_msg;
deuce's avatar
deuce committed
222
			free(mail);
223 224
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);   /* So re-load */
			if(!smb.msgs)
225
				break;
226 227
			for(smb.curmsg=0;smb.curmsg<smb.msgs;smb.curmsg++)
				if(mail[smb.curmsg].number==msg.idx.number)
228
					break;
229 230
			if(smb.curmsg>=smb.msgs)
				smb.curmsg=(smb.msgs-1);
231 232
			continue; 
		}
233

234
		if(!loadmsg(&msg,mail[smb.curmsg].number)) {	/* Message header gone */
235
			if(mismatches>5) {	/* We can't do this too many times in a row */
236
				errormsg(WHERE,ERR_CHK,"message number",mail[smb.curmsg].number);
237 238
				break; 
			}
deuce's avatar
deuce committed
239
			free(mail);
240 241
			mail=loadmail(&smb,&smb.msgs,usernumber,which,lm_mode);
			if(!smb.msgs)
242
				break;
243 244
			if(smb.curmsg>(smb.msgs-1))
				smb.curmsg=(smb.msgs-1);
245
			mismatches++;
246 247
			continue; 
		}
248 249 250 251 252 253 254 255 256 257 258 259 260
		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);
261
				SAFECOPY(str, msg.subj);					/* filenames (multiple?) in title */
262 263
				tp=str;
				while(online) {
264
					p=strchr(tp,' ');
265 266 267 268 269
					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);
270
					SAFEPRINTF3(path,"%sfile/%04u.in/%s"  /* path is path/fname */
271
						,cfg.data_dir,msg.idx.to,tp);
272
					length=(long)flength(path);
273
					if(length<1)
274
						bprintf(text[FileDoesNotExist], tp);
275 276 277 278 279 280
					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));
281
						if(length>0L && text[DownloadAttachedFileQ][0] && yesno(str3)) {
rswindell's avatar
rswindell committed
282
							{	/* Remote User */
283
								xfer_prot_menu(XFER_DOWNLOAD);
284 285 286 287
								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
288
										&& chk_ar(cfg.prot[i]->ar,&useron,&client)) {
289
										sprintf(tmp,"%c",cfg.prot[i]->mnemonic);
290 291
										strcat(str3,tmp); 
									}
292 293 294
								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
295
										&& chk_ar(cfg.prot[i]->ar,&useron,&client))
296 297
										break;
								if(i<cfg.total_prots) {
298
									error=protocol(cfg.prot[i],XFER_DOWNLOAD,path,nulstr,false);
299 300
									if(checkprotresult(cfg.prot[i],error,&fd)) {
										if(which==MAIL_YOUR)
301
											remove(path);
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
										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;
324
					while(*tp==' ') tp++; 
325
				}
326
				sprintf(str,"%sfile/%04u.in",cfg.data_dir,usernumber);
327 328
				rmdir(str); 
			}
329
			if(which==MAIL_YOUR && !(msg.hdr.attr&MSG_READ)) {
330
				mail[smb.curmsg].attr|=MSG_READ;
331 332 333 334 335 336
				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 */
337
				if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
338 339
					if(loadmsg(&msg,msg.idx.number)) {
						msg.hdr.attr|=MSG_READ;
340 341
						if(msg.hdr.attr&MSG_KILLREAD)
							msg.hdr.attr|=MSG_DELETE;
342 343
						msg.idx.attr=msg.hdr.attr;
						if((i=smb_putmsg(&smb,&msg))!=0)
344
							errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
345 346 347 348
						smb_unlockmsghdr(&smb,&msg); 
					}
					smb_unlocksmbhdr(&smb); 
				}
349 350
				if(!msg.total_hfields) {				/* unsuccessful reload */
					domsg=0;
351 352
					continue; 
				}
353
			}
354
		}
355 356 357
		else domsg=1;

		if(useron.misc&WIP) {
358 359
			strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL ?
				"allmail" : "sentmail");
360 361
			menu(str); 
		}
362 363 364

		ASYNC;
		if(which==MAIL_SENT)
365
			bprintf(text[ReadingSentMail],smb.curmsg+1,smb.msgs);
366
		else if(which==MAIL_ALL)
367
			bprintf(text[ReadingAllMail],smb.curmsg+1,smb.msgs);
368
		else
369
			bprintf(text[ReadingMail],smb.curmsg+1,smb.msgs);
370
		sprintf(str,"ADKFLNQRT?<>[]{}-+");
371
		if(SYSOP)
372
			strcat(str,"CUSPH");
373 374
		if(which!=MAIL_YOUR)
			strcat(str,"E");
375
		l=getkeys(str,smb.msgs);
376 377 378
		if(l&0x80000000L) {
			if(l==-1)	/* ctrl-c */
				break;
379
			smb.curmsg=(l&~0x80000000L)-1;
380 381
			continue; 
		}
382 383 384 385 386 387 388 389
		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;
390 391
				if((msg.hdr.attr&(MSG_NOREPLY|MSG_ANONYMOUS)) && !SYSOP) {
					bputs(text[CantReplyToMsg]);
392 393
					break; 
				}
394

395
				quotemsg(&msg,/* include tails: */TRUE);
396

397
				if(msg.from_net.addr==NULL)
398
					SAFECOPY(str,msg.from);
399
				else if(msg.from_net.type==NET_FIDO) 	/* FidoNet type */
400
					SAFEPRINTF2(str,"%s@%s",msg.from
401
						,smb_faddrtoa((faddr_t *)msg.from_net.addr,tmp));
402
				else if(msg.from_net.type==NET_INTERNET || strchr((char*)msg.from_net.addr,'@')!=NULL) {
403 404 405 406 407 408 409 410
					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);
411 412 413 414 415 416 417 418 419 420 421

				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
422
						,timestr(msg.hdr.when_written.time));
423 424 425 426

				p=strrchr(str,'@');
				if(p) { 							/* name @addr */
					replied=netmail(str,msg.subj,WM_QUOTE);
427 428
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
429 430 431 432 433 434 435
				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);
436 437
					else
						replied=false;
438 439
					sprintf(str2,text[DeleteMailQ],msg.from); 
				}
440 441 442 443 444 445

				if(replied==true && !(msg.hdr.attr&MSG_REPLIED)) {
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
					msg.idx.offset=0;
446 447 448 449 450
					if(smb_locksmbhdr(&smb)==SMB_SUCCESS) {	/* Lock the entire base */
						if(loadmsg(&msg,msg.idx.number)) {
							msg.hdr.attr|=MSG_REPLIED;
							msg.idx.attr=msg.hdr.attr;
							if((i=smb_putmsg(&smb,&msg))!=0)
451
								errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error);
452 453 454 455
							smb_unlockmsghdr(&smb,&msg); 
						}
						smb_unlocksmbhdr(&smb);
					}
456 457
				}

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

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

				if(which==MAIL_SENT)
					bputs(text[MailSentLstHdr]);
				else if(which==MAIL_ALL)
					bputs(text[MailOnSystemLstHdr]);
				else
					bputs(text[MailWaitingLstHdr]);
716
				for(;u<v;u++) {
717 718 719
					if(msg.total_hfields)
						smb_freemsgmem(&msg);
					msg.total_hfields=0;
720 721
					msg.idx.offset=mail[u].offset;
					if(!loadmsg(&msg,mail[u].number))
722 723 724 725
						continue;
					smb_unlockmsghdr(&smb,&msg);
					if(which==MAIL_ALL)
						bprintf(text[MailOnSystemLstFmt]
726
							,u+1,msg.from,msg.to
727
							,mail_listing_flag(&msg)
728 729
							,msg.subj);
					else
730
						bprintf(text[MailWaitingLstFmt],u+1
731 732 733
							,which==MAIL_SENT ? msg.to
							: (msg.hdr.attr&MSG_ANONYMOUS) && !SYSOP
							? text[Anonymous] : msg.from
734
							,mail_listing_flag(&msg)
735 736
							,msg.subj);
					smb_freemsgmem(&msg);
737 738
					msg.total_hfields=0; 
				}
739
				smb.curmsg=(u-1);
740 741 742 743
				break;
			case 'U':   /* user edit */
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
744 745 746
				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)) {
747 748 749
					bputs(text[UnknownUser]);
					domsg=false;
				} else
750
					useredit(unum);
751 752
				break;
			case 'P':   /* Purge author and all mail to/from */
753
				if(noyes(text[UeditDeleteQ]))
754 755 756
					break;
				msg.hdr.number=msg.idx.number;
				smb_getmsgidx(&smb,&msg);
757 758 759 760 761 762 763
				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++;
				}
764 765
				break;
			case '?':
766 767
				strcpy(str,which==MAIL_YOUR ? "mailread" : which==MAIL_ALL
						? "allmail" : "sentmail");
768 769
				menu(str);
				if(SYSOP && which==MAIL_SENT)
770
					menu("syssmail");
771
				else if(SYSOP && which==MAIL_YOUR)
772
					menu("sysmailr");   /* Sysop Mail Read */
773 774
				domsg=0;
				break;
775 776 777
				
		} 
	}
778 779 780 781

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

782
	if(smb.msgs)
deuce's avatar
deuce committed
783
		free(mail);
784 785 786 787 788 789 790

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

	if(cfg.sys_misc&SM_DELEMAIL) {
		if((i=smb_locksmbhdr(&smb))!=0) 			/* Lock the base, so nobody */
791
			errormsg(WHERE,ERR_LOCK,smb.file,i,smb.last_error);	/* messes with the index */
792
		else
793 794
			delmail(usernumber,which); 
	}
795 796 797

	smb_close(&smb);
	smb_stack(&smb,SMB_STACK_POP);
798
	current_msg=NULL;
799 800
}