fido.cpp 25.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/* fido.cpp */

/* Synchronet FidoNet-related routines */

/* $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 2006 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
 *																			*
 * 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"
39
#include "qwk.h"
40 41 42 43 44 45 46

faddr_t atofaddr(scfg_t* cfg, char *str);

void pt_zone_kludge(fmsghdr_t hdr,int fido)
{
	char str[256];

47
	sprintf(str,"\1INTL %hu:%hu/%hu %hu:%hu/%hu\r"
48 49 50 51 52
		,hdr.destzone,hdr.destnet,hdr.destnode
		,hdr.origzone,hdr.orignet,hdr.orignode);
	write(fido,str,strlen(str));

	if(hdr.destpoint) {
53
		sprintf(str,"\1TOPT %hu\r"
54 55 56 57
			,hdr.destpoint);
		write(fido,str,strlen(str)); }

	if(hdr.origpoint) {
58
		sprintf(str,"\1FMPT %hu\r"
59 60 61 62 63 64 65 66 67 68 69 70 71 72
			,hdr.origpoint);
		write(fido,str,strlen(str)); }
}

bool sbbs_t::lookup_netuser(char *into)
{
	char to[128],name[26],str[256],q[128];
	int i;
	FILE *stream;

	if(strchr(into,'@'))
		return(false);
	strcpy(to,into);
	strupr(to);
73
	sprintf(str,"%sqnet/users.dat", cfg.data_dir);
74 75 76
	if((stream=fnopen(&i,str,O_RDONLY))==NULL)
		return(false);
	while(!feof(stream)) {
77
		if(!fgets(str,sizeof(str),stream))
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
			break;
		str[25]=0;
		truncsp(str);
		strcpy(name,str);
		strupr(name);
		str[35]=0;
		truncsp(str+27);
		sprintf(q,"Do you mean %s @%s",str,str+27);
		if(strstr(name,to) && yesno(q)) {
			fclose(stream);
			sprintf(into,"%s@%s",str,str+27);
			return(true); }
		if(sys_status&SS_ABORT)
			break; }
	fclose(stream);
	return(false);
}

/****************************************************************************/
97
/* Send FidoNet/QWK/Internet NetMail from BBS								*/
98 99 100
/****************************************************************************/
bool sbbs_t::netmail(char *into, char *title, long mode)
{
101 102 103 104 105
	char	str[256],subj[128],to[256],fname[128],*buf,*p,ch;
	char 	tmp[512];
	int		file,fido,x,cc_found,cc_sent;
	uint	i;
	long	length,l;
106 107
	faddr_t addr;
	fmsghdr_t hdr;
108
	struct tm tm;
109 110 111 112 113 114

	if(useron.etoday>=cfg.level_emailperday[useron.level] && !SYSOP) {
		bputs(text[TooManyEmailsToday]);
		return(false); 
	}

rswindell's avatar
rswindell committed
115
	SAFECOPY(subj,title);
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

	strcpy(to,into);

	lookup_netuser(to);

	p=strrchr(to,'@');      /* Find '@' in name@addr */
	if(p && !isdigit(*(p+1)) && !strchr(p,'.') && !strchr(p,':')) {
		mode&=~WM_FILE;
		qnetmail(to,title,mode|WM_NETMAIL);
		return(false); }
	if(!cfg.total_faddrs || p==NULL || !strchr(p+1,'/')) {
		if(!p && cfg.dflt_faddr.zone)
			addr=cfg.dflt_faddr;
		else if(cfg.inetmail_misc&NMAIL_ALLOW) {
			if(mode&WM_FILE && !SYSOP && !(cfg.inetmail_misc&NMAIL_FILE))
				mode&=~WM_FILE;
			return(inetmail(into,title,mode|WM_NETMAIL));
		}
		else if(cfg.dflt_faddr.zone)
			addr=cfg.dflt_faddr;
		else {
137 138 139 140
			bputs(text[InvalidNetMailAddr]);
			return(false); 
		} 
	} else {
141 142
		addr=atofaddr(&cfg,p+1); 	/* Get fido address */
		*p=0;					/* Chop off address */
143
	}
144 145 146 147 148 149 150

	if(mode&WM_FILE && !SYSOP && !(cfg.netmail_misc&NMAIL_FILE))
		mode&=~WM_FILE;

	if((!SYSOP && !(cfg.netmail_misc&NMAIL_ALLOW)) || useron.rest&FLAG('M')
		|| !cfg.total_faddrs) {
		bputs(text[NoNetMailAllowed]);
151 152
		return(false); 
	}
153 154 155 156 157

	truncsp(to);				/* Truncate off space */

	memset(&hdr,0,sizeof(hdr));   /* Initialize header to null */
	strcpy(hdr.from,cfg.netmail_misc&NMAIL_ALIAS ? useron.alias : useron.name);
158
	SAFECOPY(hdr.to,to);
159 160 161 162 163 164

	/* Look-up in nodelist? */

	if(cfg.netmail_cost && !(useron.exempt&FLAG('S'))) {
		if(useron.cdt+useron.freecdt<cfg.netmail_cost) {
			bputs(text[NotEnoughCredits]);
165 166
			return(false); 
		}
167 168
		sprintf(str,text[NetMailCostContinueQ],cfg.netmail_cost);
		if(noyes(str))
169 170
			return(false); 
	}
171 172

	now=time(NULL);
173
	if(localtime_r(&now,&tm)!=NULL)
174
		sprintf(hdr.time,"%02u %3.3s %02u  %02u:%02u:%02u"
175 176
			,tm.tm_mday,mon[tm.tm_mon],TM_YEAR(tm.tm_year)
			,tm.tm_hour,tm.tm_min,tm.tm_sec);
177 178 179 180 181 182 183 184 185 186 187 188

	hdr.destzone	=addr.zone;
	hdr.destnet 	=addr.net;
	hdr.destnode	=addr.node;
	hdr.destpoint	=addr.point;

	for(i=0;i<cfg.total_faddrs;i++)
		if(addr.zone==cfg.faddr[i].zone && addr.net==cfg.faddr[i].net)
			break;
	if(i==cfg.total_faddrs) {
		for(i=0;i<cfg.total_faddrs;i++)
			if(addr.zone==cfg.faddr[i].zone)
189 190
				break; 
	}
191 192 193 194 195 196 197
	if(i==cfg.total_faddrs)
		i=0;
	hdr.origzone	=cfg.faddr[i].zone;
	hdr.orignet 	=cfg.faddr[i].net;
	hdr.orignode	=cfg.faddr[i].node;
	hdr.origpoint	=cfg.faddr[i].point;

198 199
	smb_faddrtoa(&cfg.faddr[i],str);
	bprintf(text[NetMailing],hdr.to,smb_faddrtoa(&addr,tmp),hdr.from,str);
200 201 202 203 204 205 206 207 208 209 210 211 212

	hdr.attr=(FIDO_LOCAL|FIDO_PRIVATE);

	if(cfg.netmail_misc&NMAIL_CRASH) hdr.attr|=FIDO_CRASH;
	if(cfg.netmail_misc&NMAIL_HOLD)  hdr.attr|=FIDO_HOLD;
	if(cfg.netmail_misc&NMAIL_KILL)  hdr.attr|=FIDO_KILLSENT;
	if(mode&WM_FILE) hdr.attr|=FIDO_FILE;

	sprintf(str,"%sNETMAIL.MSG", cfg.node_dir);
	remove(str);	/* Just incase it's already there */
	// mode&=~WM_FILE;
	if(!writemsg(str,nulstr,subj,WM_NETMAIL|mode,INVALID_SUB,into)) {
		bputs(text[Aborted]);
213 214
		return(false); 
	}
215 216 217

	if(mode&WM_FILE) {
		strcpy(fname,subj);
218
		sprintf(str,"%sfile/%04u.out", cfg.data_dir, useron.number);
rswindell's avatar
rswindell committed
219
		MKDIR(str);
220 221 222
		strcpy(tmp, cfg.data_dir);
		if(tmp[0]=='.')    /* Relative path */
			sprintf(tmp,"%s%s", cfg.node_dir, cfg.data_dir);
223
		sprintf(str,"%sfile/%04u.out/%s",tmp,useron.number,fname);
224
		strcpy(subj,str);
225
		if(fexistcase(str)) {
226 227
			bputs(text[FileAlreadyThere]);
			return(false); }
rswindell's avatar
rswindell committed
228
#if 0	/* no such thing as local logon */
229 230 231 232
		if(online==ON_LOCAL) {		/* Local upload */
			bputs(text[EnterPath]);
			if(!getstr(str,60,K_LINE|K_UPPER)) {
				bputs(text[Aborted]);
233 234
				return(false); 
			}
235 236 237
			backslash(str);
			strcat(str,fname);
			if(mv(str,subj,1))
238
				return(false); 
rswindell's avatar
rswindell committed
239 240 241
		} else 
#endif
		{ /* Remote */
242
			xfer_prot_menu(XFER_UPLOAD);
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
			mnemonics(text[ProtocolOrQuit]);
			strcpy(str,"Q");
			for(x=0;x<cfg.total_prots;x++)
				if(cfg.prot[x]->ulcmd[0] && chk_ar(cfg.prot[x]->ar,&useron)) {
					sprintf(tmp,"%c",cfg.prot[x]->mnemonic);
					strcat(str,tmp); }
			ch=(char)getkeys(str,0);
			if(ch=='Q' || sys_status&SS_ABORT) {
				bputs(text[Aborted]);
				return(false); }
			for(x=0;x<cfg.total_prots;x++)
				if(cfg.prot[x]->ulcmd[0] && cfg.prot[x]->mnemonic==ch
					&& chk_ar(cfg.prot[x]->ar,&useron))
					break;
			if(x<cfg.total_prots)	/* This should be always */
258
				protocol(cfg.prot[x],XFER_UPLOAD,subj,nulstr,true); 
259
		}
260 261 262
		sprintf(tmp,"%s%s",cfg.temp_dir,title);
		if(!fexistcase(subj) && fexistcase(tmp))
			mv(tmp,subj,0);
263 264 265 266 267
		l=flength(subj);
		if(l>0)
			bprintf(text[FileNBytesReceived],fname,ultoac(l,tmp));
		else {
			bprintf(text[FileNotReceived],fname);
268 269 270
			return(false); 
		} 
	}
271 272 273 274 275

	p=subj;
	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"CR:",3)) {     /* Crash over-ride by sysop */
		p+=3;				/* skip CR: */
276
		if(*p==' ') p++; 	/* skip extra space if it exists */
277 278 279 280 281
		hdr.attr|=FIDO_CRASH; }

	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"FR:",3)) {     /* File request */
		p+=3;				/* skip FR: */
282
		if(*p==' ') p++;
283 284 285 286 287
		hdr.attr|=FIDO_FREQ; }

	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"RR:",3)) {     /* Return receipt request */
		p+=3;				/* skip RR: */
288
		if(*p==' ') p++;
289 290 291 292 293
		hdr.attr|=FIDO_RRREQ; }

	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"FA:",3)) {     /* File Attachment */
		p+=3;				/* skip FA: */
294
		if(*p==' ') p++;
295 296
		hdr.attr|=FIDO_FILE; }

297
	SAFECOPY(hdr.subj,p);
298 299 300 301 302 303

	sprintf(str,"%sNETMAIL.MSG", cfg.node_dir);
	if((file=nopen(str,O_RDONLY))==-1) {
		errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
		return(false); }
	length=filelength(file);
deuce's avatar
deuce committed
304
	if((buf=(char *)malloc(length))==NULL) {
305 306 307 308 309 310 311 312 313
		close(file);
		errormsg(WHERE,ERR_ALLOC,str,length);
		return(false); }
	read(file,buf,length);
	close(file);

	cc_sent=0;
	while(1) {
		for(i=1;i;i++) {
314
			sprintf(str,"%s%u.msg", cfg.netmail_dir,i);
315
			if(!fexistcase(str))
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
				break; }
		if(!i) {
			bputs(text[TooManyEmailsToday]);
			return(false); }
		if((fido=nopen(str,O_WRONLY|O_CREAT|O_EXCL))==-1) {
			errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_EXCL);
			return(false); }
		write(fido,&hdr,sizeof(hdr));

		pt_zone_kludge(hdr,fido);

		if(cfg.netmail_misc&NMAIL_DIRECT) {
			sprintf(str,"\1FLAGS DIR\r\n");
			write(fido,str,strlen(str)); }
		if(mode&WM_FILE) {
			sprintf(str,"\1FLAGS KFS\r\n");
			write(fido,str,strlen(str)); }

		if(cc_sent) {
			sprintf(str,"* Originally to: %s\r\n\r\n",into);
			write(fido,str,strlen(str)); }

		l=0L;
		while(l<length) {
340
			if(buf[l]==CTRL_A)	/* Ctrl-A, so skip it and the next char */
341 342 343 344 345 346 347 348 349 350 351 352
				l++;
			else if(buf[l]!=LF) {
				if((uchar)buf[l]==0x8d)   /* r0dent i converted to normal i */
					buf[l]='i';
				write(fido,buf+l,1); }
			l++; }
		l=0;
		write(fido,&l,1);	/* Null terminator */
		close(fido);

		useron.emails++;
		logon_emails++;
353
		putuserrec(&cfg,useron.number,U_EMAILS,5,ultoa(useron.emails,tmp,10)); 
354
		useron.etoday++;
355
		putuserrec(&cfg,useron.number,U_ETODAY,5,ultoa(useron.etoday,tmp,10));
356 357 358 359

		if(!(useron.exempt&FLAG('S')))
			subtract_cdt(&cfg,&useron,cfg.netmail_cost);
		if(mode&WM_FILE)
360 361
			sprintf(str,"%s sent NetMail file attachment to %s (%s)"
				,useron.alias
362
				,hdr.to,smb_faddrtoa(&addr,tmp));
363
		else
364 365
			sprintf(str,"%s sent NetMail to %s (%s)"
				,useron.alias
366
				,hdr.to,smb_faddrtoa(&addr,tmp));
367 368 369 370 371 372 373 374 375 376 377 378
		logline("EN",str);

		cc_found=0;
		for(l=0;l<length && cc_found<=cc_sent;l++)
			if(l+3<length && !strnicmp(buf+l,"CC:",3)) {
				cc_found++;
				l+=2; }
			else {
				while(l<length && *(buf+l)!=LF)
					l++; }
		if(!cc_found)
			break;
379
		while(l<length && *(buf+l)==' ') l++;
380 381 382 383 384 385 386 387 388
		for(i=0;l<length && *(buf+l)!=LF && i<128;i++,l++)
			str[i]=buf[l];
		if(!i)
			break;
		str[i]=0;
		p=strrchr(str,'@');
		if(p) {
			addr=atofaddr(&cfg,p+1);
			*p=0;
389
			SAFECOPY(hdr.to,str); }
390 391 392 393 394 395 396 397 398 399
		else {
			atofaddr(&cfg,str);
			strcpy(hdr.to,"Sysop"); }
		hdr.destzone	=addr.zone;
		hdr.destnet 	=addr.net;
		hdr.destnode	=addr.node;
		hdr.destpoint	=addr.point;
		cc_sent++; }

	if(cfg.netmail_sem[0])		/* update semaphore file */
400
		ftouch(cmdstr(cfg.netmail_sem,nulstr,nulstr,NULL));
401

deuce's avatar
deuce committed
402
	free(buf);
403 404 405 406 407 408 409 410
	return(true);
}

/****************************************************************************/
/* Send NetMail from QWK REP Packet 										*/
/****************************************************************************/
void sbbs_t::qwktonetmail(FILE *rep, char *block, char *into, uchar fromhub)
{
deuce's avatar
deuce committed
411
	char	*qwkbuf,to[129],name[129],sender[129],senderaddr[129]
412 413
			   ,str[256],*p,*cp,*addr,fulladdr[129],ch;
	char 	tmp[512];
414
	int 	i,fido,inet=0,qnet=0;
deuce's avatar
64-bit  
deuce committed
415 416
	ushort	net;
	uint16_t xlat;
417 418 419 420 421 422 423 424 425 426
	long	l,offset,length,m,n;
	faddr_t fidoaddr;
    fmsghdr_t hdr;
	smbmsg_t msg;
	struct	tm tm;

	if(useron.rest&FLAG('M')) { 
		bputs(text[NoNetMailAllowed]);
		return; }

427 428 429 430 431 432
	to[0]=0;
	name[0]=0;
	sender[0]=0;
	senderaddr[0]=0;
	fulladdr[0]=0;

433 434 435 436 437 438
	sprintf(str,"%.6s",block+116);
	n=atol(str);	  /* i = number of 128 byte records */

	if(n<2L || n>999999L) {
		errormsg(WHERE,ERR_CHK,"QWK blocks",n);
		return; }
deuce's avatar
deuce committed
439
	if((qwkbuf=(char *)malloc(n*QWK_BLOCK_LEN))==NULL) {
440
		errormsg(WHERE,ERR_ALLOC,nulstr,n*QWK_BLOCK_LEN);
441
		return; }
442 443
	memcpy((char *)qwkbuf,block,QWK_BLOCK_LEN);
	fread(qwkbuf+QWK_BLOCK_LEN,n-1,QWK_BLOCK_LEN,rep);
444 445

	if(into==NULL)
446
		sprintf(to,"%-128.128s",(char *)qwkbuf+QWK_BLOCK_LEN);  /* To user on first line */
447
	else
448
		SAFECOPY(to,into);
449

450
	p=strchr(to,QWK_NEWLINE);		/* chop off at first CR */
451 452
	if(p) *p=0;

453
	SAFECOPY(name,to);
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
	p=strchr(name,'@');
	if(p) *p=0;
	truncsp(name);


	p=strrchr(to,'@');       /* Find '@' in name@addr */
	if(p && !isdigit(*(p+1)) && !strchr(p,'.') && !strchr(p,':')) { /* QWKnet */
		qnet=1;
		*p=0; }
	else if(p==NULL || !isdigit(*(p+1)) || !cfg.total_faddrs) {
		if(p==NULL && cfg.dflt_faddr.zone)
			fidoaddr=cfg.dflt_faddr;
		else if(cfg.inetmail_misc&NMAIL_ALLOW) {	/* Internet */
			inet=1;
			}
		else if(cfg.dflt_faddr.zone)
			fidoaddr=cfg.dflt_faddr;
		else {
472
			bputs(text[InvalidNetMailAddr]);
deuce's avatar
deuce committed
473
			free(qwkbuf);
474 475 476 477 478 479 480 481 482 483
			return; } }
	else {
		fidoaddr=atofaddr(&cfg,p+1); 	/* Get fido address */
		*p=0;					/* Chop off address */
		}


	if(!inet && !qnet &&		/* FidoNet */
		((!SYSOP && !(cfg.netmail_misc&NMAIL_ALLOW)) || !cfg.total_faddrs)) {
		bputs(text[NoNetMailAllowed]);
deuce's avatar
deuce committed
484
		free(qwkbuf);
485 486 487 488 489
		return; }

	truncsp(to);			/* Truncate off space */

	if(!stricmp(to,"SBBS") && !SYSOP && qnet) {
deuce's avatar
deuce committed
490
		free(qwkbuf);
491 492
		return; }

493
	l=QWK_BLOCK_LEN;		/* Start of message text */
494 495 496 497

	if(qnet || inet) {

		if(into==NULL) {	  /* If name@addr on first line, skip first line */
498
			while(l<(n*QWK_BLOCK_LEN) && qwkbuf[l]!=QWK_NEWLINE) l++;
499 500 501 502 503
			l++; }

		memset(&msg,0,sizeof(smbmsg_t));
		msg.hdr.version=smb_ver();
		msg.hdr.when_imported.time=time(NULL);
504
		msg.hdr.when_imported.zone=sys_timezone(&cfg);
505 506 507 508 509 510

		if(fromhub || useron.rest&FLAG('Q')) {
			net=NET_QWK;
			smb_hfield(&msg,SENDERNETTYPE,sizeof(net),&net);
			if(!strncmp(qwkbuf+l,"@VIA:",5)) {
				sprintf(str,"%.128s",qwkbuf+l+5);
511
				cp=strchr(str,QWK_NEWLINE);
512 513 514
				if(cp) *cp=0;
				l+=strlen(str)+1;
				cp=str;
515
				while(*cp && *cp<=' ') cp++;
516 517 518 519 520 521
				sprintf(senderaddr,"%s/%s"
					,fromhub ? cfg.qhub[fromhub-1]->id : useron.alias,cp);
				strupr(senderaddr);
				smb_hfield(&msg,SENDERNETADDR,strlen(senderaddr),senderaddr); }
			else {
				if(fromhub)
522
					SAFECOPY(senderaddr, cfg.qhub[fromhub-1]->id);
523
				else
524
					SAFECOPY(senderaddr, useron.alias);
525 526 527 528
				strupr(senderaddr);
				smb_hfield(&msg,SENDERNETADDR,strlen(senderaddr),senderaddr); }
			sprintf(sender,"%.25s",block+46); }    /* From name */
		else {	/* Not Networked */
529
			msg.hdr.when_written.zone=sys_timezone(&cfg);
530 531
			sprintf(str,"%u",useron.number);
			smb_hfield(&msg,SENDEREXT,strlen(str),str);
532
			SAFECOPY(sender,(qnet || cfg.inetmail_misc&NMAIL_ALIAS)
533 534 535 536 537 538 539 540 541 542
				? useron.alias : useron.name);
			}
		truncsp(sender);
		smb_hfield(&msg,SENDER,strlen(sender),sender);
		if(fromhub)
			msg.idx.from=0;
		else
			msg.idx.from=useron.number;
		if(!strncmp(qwkbuf+l,"@TZ:",4)) {
			sprintf(str,"%.128s",qwkbuf+l);
543
			cp=strchr(str,QWK_NEWLINE);
544 545 546
			if(cp) *cp=0;
			l+=strlen(str)+1;
			cp=str+4;
547
			while(*cp && *cp<=' ') cp++;
548 549
			msg.hdr.when_written.zone=(short)ahtoul(cp); }
		else
550
			msg.hdr.when_written.zone=sys_timezone(&cfg);
551 552 553 554 555 556 557 558 559 560 561
		memset(&tm,0,sizeof(tm));
		tm.tm_mon=((qwkbuf[8]&0xf)*10)+(qwkbuf[9]&0xf);
		if(tm.tm_mon) tm.tm_mon--;	/* 0 based */
		tm.tm_mday=((qwkbuf[11]&0xf)*10)+(qwkbuf[12]&0xf);
		tm.tm_year=((qwkbuf[14]&0xf)*10)+(qwkbuf[15]&0xf);
		if(tm.tm_year<Y2K_2DIGIT_WINDOW)
			tm.tm_year+=100;
		tm.tm_hour=((qwkbuf[16]&0xf)*10)+(qwkbuf[17]&0xf);
		tm.tm_min=((qwkbuf[19]&0xf)*10)+(qwkbuf[20]&0xf);  /* From QWK time */
		tm.tm_sec=0;

562
		tm.tm_isdst=-1;	/* Do not adjust for DST */
563 564 565 566
		msg.hdr.when_written.time=mktime(&tm);

		sprintf(str,"%.25s",block+71);              /* Title */
		smb_hfield(&msg,SUBJECT,strlen(str),str);
567
	}
568 569 570 571 572 573 574 575 576

	if(qnet) {

		p++;
		addr=p;
		msg.idx.to=qwk_route(addr,fulladdr);
		if(!fulladdr[0]) {		/* Invalid address, so BOUNCE it */
		/**
			errormsg(WHERE,ERR_CHK,addr,0);
deuce's avatar
deuce committed
577
			free(qwkbuf);
578 579 580 581 582 583
			smb_freemsgmem(msg);
			return;
		**/
			smb_hfield(&msg,SENDER,strlen(cfg.sys_id),cfg.sys_id);
			msg.idx.from=0;
			msg.idx.to=useron.number;
584 585 586
			SAFECOPY(to,sender);
			SAFECOPY(fulladdr,senderaddr);
			SAFEPRINTF(str,"BADADDR: %s",addr);
587 588 589 590
			smb_hfield(&msg,SUBJECT,strlen(str),str);
			net=NET_NONE;
			smb_hfield(&msg,SENDERNETTYPE,sizeof(net),&net);
		}
591
		/* This is required for fixsmb to be able to rebuild the index */
592
		SAFEPRINTF(str,"%u",msg.idx.to);
593
		smb_hfield_str(&msg,RECIPIENTEXT,str);
594 595 596 597 598 599

		smb_hfield(&msg,RECIPIENT,strlen(name),name);
		net=NET_QWK;
		smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(net),&net);

		truncsp(fulladdr);
600 601
		if(fulladdr[0])
			smb_hfield(&msg,RECIPIENTNETADDR,strlen(fulladdr),fulladdr);
602 603 604 605 606 607 608 609

		bprintf(text[NetMailing],to,fulladdr,sender,cfg.sys_id); }

	if(inet) {				/* Internet E-mail */

		if(cfg.inetmail_cost && !(useron.exempt&FLAG('S'))) {
			if(useron.cdt+useron.freecdt<cfg.inetmail_cost) {
				bputs(text[NotEnoughCredits]);
deuce's avatar
deuce committed
610
				free(qwkbuf);
611 612 613 614
				smb_freemsgmem(&msg);
				return; }
			sprintf(str,text[NetMailCostContinueQ],cfg.inetmail_cost);
			if(noyes(str)) {
deuce's avatar
deuce committed
615
				free(qwkbuf);
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
				smb_freemsgmem(&msg);
				return; } }

		net=NET_INTERNET;
		smb_hfield(&msg,RECIPIENT,strlen(name),name);
		msg.idx.to=0;   /* Out-bound NetMail set to 0 */
		smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(net),&net);
		smb_hfield(&msg,RECIPIENTNETADDR,strlen(to),to);

		bprintf(text[NetMailing],name,to
			,cfg.inetmail_misc&NMAIL_ALIAS ? useron.alias : useron.name
			,cfg.sys_inetaddr); }

	if(qnet || inet) {

		bputs(text[WritingIndx]);

		if((i=smb_stack(&smb,SMB_STACK_PUSH))!=0) {
			errormsg(WHERE,ERR_OPEN,"MAIL",i);
deuce's avatar
deuce committed
635
			free(qwkbuf);
636 637
			smb_freemsgmem(&msg);
			return; }
638
		sprintf(smb.file,"%smail", cfg.data_dir);
639
		smb.retry_time=cfg.smb_retry_time;
640
		smb.subnum=INVALID_SUB;
641 642 643
		if((i=smb_open(&smb))!=0) {
			smb_stack(&smb,SMB_STACK_POP);
			errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
deuce's avatar
deuce committed
644
			free(qwkbuf);
645 646 647 648 649
			smb_freemsgmem(&msg);
			return; }

		if(smb_fgetlength(smb.shd_fp)<1L) {   /* Create it if it doesn't exist */
			smb.status.max_crcs=cfg.mail_maxcrcs;
650
			smb.status.max_msgs=0;
651 652 653 654 655 656
			smb.status.max_age=cfg.mail_maxage;
			smb.status.attr=SMB_EMAIL;
			if((i=smb_create(&smb))!=0) {
				smb_close(&smb);
				smb_stack(&smb,SMB_STACK_POP);
				errormsg(WHERE,ERR_CREATE,smb.file,i,smb.last_error);
deuce's avatar
deuce committed
657
				free(qwkbuf);
658 659 660 661 662 663 664 665 666 667 668
				smb_freemsgmem(&msg);
				return; } }

		length=n*256L;	// Extra big for CRLF xlat, was (n-1L)*256L (03/16/96)


		if(length&0xfff00000UL || !length) {
			smb_close(&smb);
			smb_stack(&smb,SMB_STACK_POP);
			sprintf(str,"REP msg (%ld)",n);
			errormsg(WHERE,ERR_LEN,str,length);
deuce's avatar
deuce committed
669
			free(qwkbuf);
670 671 672 673 674 675 676
			smb_freemsgmem(&msg);
			return; }

		if((i=smb_open_da(&smb))!=0) {
			smb_close(&smb);
			smb_stack(&smb,SMB_STACK_POP);
			errormsg(WHERE,ERR_OPEN,smb.file,i,smb.last_error);
deuce's avatar
deuce committed
677
			free(qwkbuf);
678 679 680 681 682 683 684 685 686 687
			smb_freemsgmem(&msg);
			return; }
		if(cfg.sys_misc&SM_FASTMAIL)
			offset=smb_fallocdat(&smb,length,1);
		else
			offset=smb_allocdat(&smb,length,1);
		smb_close_da(&smb);

		smb_fseek(smb.sdt_fp,offset,SEEK_SET);
		xlat=XLAT_NONE;
688
		smb_fwrite(&smb,&xlat,2,smb.sdt_fp);
689
		m=2;
690
		for(;l<n*QWK_BLOCK_LEN && m<length;l++) {
691 692
			if(qwkbuf[l]==0 || qwkbuf[l]==LF)
				continue;
693
			if(qwkbuf[l]==QWK_NEWLINE) {
694
				smb_fwrite(&smb,crlf,2,smb.sdt_fp);
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
				m+=2;
				continue; }
			smb_fputc(qwkbuf[l],smb.sdt_fp);
			m++; }

		for(ch=0;m<length;m++)			/* Pad out with NULLs */
			smb_fputc(ch,smb.sdt_fp);
		smb_fflush(smb.sdt_fp);

		msg.hdr.offset=offset;

		smb_dfield(&msg,TEXT_BODY,length);

		i=smb_addmsghdr(&smb,&msg,SMB_SELFPACK);
		smb_close(&smb);
		smb_stack(&smb,SMB_STACK_POP);

		smb_freemsgmem(&msg);
713 714
		if(i!=SMB_SUCCESS) {
			errormsg(WHERE,ERR_WRITE,smb.file,i,smb.last_error); 
715
			smb_freemsgdat(&smb,offset,length,1);
716
		}
717 718 719
		else {		/* Successful */
			if(inet) {
				if(cfg.inetmail_sem[0]) 	 /* update semaphore file */
720
					ftouch(cmdstr(cfg.inetmail_sem,nulstr,nulstr,NULL));
721 722 723 724 725
				if(!(useron.exempt&FLAG('S')))
					subtract_cdt(&cfg,&useron,cfg.inetmail_cost); }

			useron.emails++;
			logon_emails++;
726
			putuserrec(&cfg,useron.number,U_EMAILS,5,ultoa(useron.emails,tmp,10)); 
727
			useron.etoday++;
728
			putuserrec(&cfg,useron.number,U_ETODAY,5,ultoa(useron.etoday,tmp,10));
729

730 731
			sprintf(str,"%s sent %s NetMail to %s (%s) via QWK"
				,useron.alias
732 733 734
				,qnet ? "QWK":"Internet",name,qnet ? fulladdr : to);
			logline("EN",str); }

deuce's avatar
deuce committed
735
		free((char *)qwkbuf);
736 737 738 739 740 741
		return; }


	/****************************** FidoNet **********************************/

	if(!fidoaddr.zone || !cfg.netmail_dir[0]) {  // No fido netmail allowed
742
		bputs(text[InvalidNetMailAddr]);
deuce's avatar
deuce committed
743
		free(qwkbuf);
744 745
		return; 
	}
746 747 748 749 750 751 752 753 754 755

	memset(&hdr,0,sizeof(hdr));   /* Initialize header to null */

	if(fromhub || useron.rest&FLAG('Q')) {
		sprintf(str,"%.25s",block+46);              /* From */
		truncsp(str);
		sprintf(tmp,"@%s",fromhub ? cfg.qhub[fromhub-1]->id : useron.alias);
		strupr(tmp);
		strcat(str,tmp); }
	else
756
		SAFECOPY(str,cfg.netmail_misc&NMAIL_ALIAS ? useron.alias : useron.name);
757
	SAFECOPY(hdr.from,str);
758

759
	SAFECOPY(hdr.to,to);
760 761 762 763 764 765

	/* Look-up in nodelist? */

	if(cfg.netmail_cost && !(useron.exempt&FLAG('S'))) {
		if(useron.cdt+useron.freecdt<cfg.netmail_cost) {
			bputs(text[NotEnoughCredits]);
deuce's avatar
deuce committed
766
			free(qwkbuf);
767 768 769
			return; }
		sprintf(str,text[NetMailCostContinueQ],cfg.netmail_cost);
		if(noyes(str)) {
deuce's avatar
deuce committed
770
			free(qwkbuf);
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
			return; } }

	hdr.destzone	=fidoaddr.zone;
	hdr.destnet 	=fidoaddr.net;
	hdr.destnode	=fidoaddr.node;
	hdr.destpoint	=fidoaddr.point;

	for(i=0;i<cfg.total_faddrs;i++)
		if(fidoaddr.zone==cfg.faddr[i].zone && fidoaddr.net==cfg.faddr[i].net)
			break;
	if(i==cfg.total_faddrs) {
		for(i=0;i<cfg.total_faddrs;i++)
			if(fidoaddr.zone==cfg.faddr[i].zone)
				break; }
	if(i==cfg.total_faddrs)
		i=0;
	hdr.origzone	=cfg.faddr[i].zone;
	hdr.orignet 	=cfg.faddr[i].net;
	hdr.orignode	=cfg.faddr[i].node;
	hdr.origpoint   =cfg.faddr[i].point;

792 793
	smb_faddrtoa(&cfg.faddr[i],str);
	bprintf(text[NetMailing],hdr.to,smb_faddrtoa(&fidoaddr,tmp),hdr.from,str);
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
	tm.tm_mon=((qwkbuf[8]&0xf)*10)+(qwkbuf[9]&0xf);
	if (tm.tm_mon) tm.tm_mon--;
	tm.tm_mday=((qwkbuf[11]&0xf)*10)+(qwkbuf[12]&0xf);
	tm.tm_year=((qwkbuf[14]&0xf)*10)+(qwkbuf[15]&0xf)+1900;
	tm.tm_hour=((qwkbuf[16]&0xf)*10)+(qwkbuf[17]&0xf);
	tm.tm_min=((qwkbuf[19]&0xf)*10)+(qwkbuf[20]&0xf);		/* From QWK time */
	tm.tm_sec=0;
	sprintf(hdr.time,"%02u %3.3s %02u  %02u:%02u:%02u"          /* To FidoNet */
		,tm.tm_mday,mon[tm.tm_mon],TM_YEAR(tm.tm_year)
		,tm.tm_hour,tm.tm_min,tm.tm_sec);
	hdr.attr=(FIDO_LOCAL|FIDO_PRIVATE);

	if(cfg.netmail_misc&NMAIL_CRASH) hdr.attr|=FIDO_CRASH;
	if(cfg.netmail_misc&NMAIL_HOLD)  hdr.attr|=FIDO_HOLD;
	if(cfg.netmail_misc&NMAIL_KILL)  hdr.attr|=FIDO_KILLSENT;

	sprintf(str,"%.25s",block+71);      /* Title */
	truncsp(str);
	p=str;
	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"CR:",3)) {     /* Crash over-ride by sysop */
		p+=3;               /* skip CR: */
816
		if(*p==' ') p++;     /* skip extra space if it exists */
817 818 819 820 821
		hdr.attr|=FIDO_CRASH; }

	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"FR:",3)) {     /* File request */
		p+=3;               /* skip FR: */
822
		if(*p==' ') p++;
823 824 825 826 827
		hdr.attr|=FIDO_FREQ; }

	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"RR:",3)) {     /* Return receipt request */
		p+=3;               /* skip RR: */
828
		if(*p==' ') p++;
829 830 831 832 833
		hdr.attr|=FIDO_RRREQ; }

	if((SYSOP || useron.exempt&FLAG('F'))
		&& !strnicmp(p,"FA:",3)) {     /* File attachment */
		p+=3;				/* skip FA: */
834
		if(*p==' ') p++;
835 836
		hdr.attr|=FIDO_FILE; }

837
	SAFECOPY(hdr.subj,p);
838 839

	for(i=1;i;i++) {
840
		sprintf(str,"%s%u.msg", cfg.netmail_dir,i);
841
		if(!fexistcase(str))
842 843 844 845 846
			break; }
	if(!i) {
		bputs(text[TooManyEmailsToday]);
		return; }
	if((fido=nopen(str,O_WRONLY|O_CREAT|O_EXCL))==-1) {
deuce's avatar
deuce committed
847
		free(qwkbuf);
848 849 850 851 852 853 854 855 856 857
		errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_EXCL);
		return; }
	write(fido,&hdr,sizeof(hdr));

	pt_zone_kludge(hdr,fido);

	if(cfg.netmail_misc&NMAIL_DIRECT) {
		sprintf(str,"\1FLAGS DIR\r\n");
		write(fido,str,strlen(str)); }

858
	l=QWK_BLOCK_LEN;
859 860

	if(into==NULL) {	  /* If name@addr on first line, skip first line */
861
		while(l<n*QWK_BLOCK_LEN && qwkbuf[l]!=QWK_NEWLINE) l++;
862 863
		l++; }

864
	while(l<n*QWK_BLOCK_LEN) {
865
		if(qwkbuf[l]==CTRL_A)   /* Ctrl-A, so skip it and the next char */
866 867
			l++;
		else if(qwkbuf[l]!=LF) {
868
			if(qwkbuf[l]==QWK_NEWLINE) /* QWK cr/lf char converted to hard CR */
869 870 871 872 873 874
				qwkbuf[l]=CR;
			write(fido,(char *)qwkbuf+l,1); }
		l++; }
	l=0;
	write(fido,&l,1);	/* Null terminator */
	close(fido);
deuce's avatar
deuce committed
875
	free((char *)qwkbuf);
876
	if(cfg.netmail_sem[0])		/* update semaphore file */
877
		ftouch(cmdstr(cfg.netmail_sem,nulstr,nulstr,NULL));
878 879 880 881 882
	if(!(useron.exempt&FLAG('S')))
		subtract_cdt(&cfg,&useron,cfg.netmail_cost);

	useron.emails++;
	logon_emails++;
883
	putuserrec(&cfg,useron.number,U_EMAILS,5,ultoa(useron.emails,tmp,10)); 
884
	useron.etoday++;
885
	putuserrec(&cfg,useron.number,U_ETODAY,5,ultoa(useron.etoday,tmp,10));
886

887 888
	sprintf(str,"%s sent NetMail to %s @%s via QWK"
		,useron.alias
889
		,hdr.to,smb_faddrtoa(&fidoaddr,tmp));
890
	logline("EN",str);
891
}
892

893 894 895 896 897 898 899
/****************************************************************************/
/* Returns the FidoNet address kept in str as ASCII.                        */
/****************************************************************************/
faddr_t atofaddr(scfg_t* cfg, char *str)
{
	char *p;
	faddr_t addr;
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924

	addr.zone=addr.net=addr.node=addr.point=0;
	if((p=strchr(str,':'))!=NULL) {
		addr.zone=atoi(str);
		addr.net=atoi(p+1); }
	else {
		if(cfg->total_faddrs)
			addr.zone=cfg->faddr[0].zone;
		else
			addr.zone=1;
		addr.net=atoi(str); }
	if(!addr.zone)              /* no such thing as zone 0 */
		addr.zone=1;
	if((p=strchr(str,'/'))!=NULL)
		addr.node=atoi(p+1);
	else {
		if(cfg->total_faddrs)
			addr.net=cfg->faddr[0].net;
		else
			addr.net=1;
		addr.node=atoi(str); }
	if((p=strchr(str,'.'))!=NULL)
		addr.point=atoi(p+1);
	return(addr);
}