Newer
Older
/* Synchronet network mail-related functions */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* 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 *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
#include "qwk.h"
static bool pt_zone_kludge(const fmsghdr_t* hdr, int fido)
snprintf(str, sizeof str, "\1INTL %hu:%hu/%hu %hu:%hu/%hu\r"
, hdr->destzone, hdr->destnet, hdr->destnode
, hdr->origzone, hdr->orignet, hdr->orignode);
if (write(fido, str, strlen(str)) < 1)
snprintf(str, sizeof str, "\1TOPT %hu\r"
, hdr->destpoint);
if (write(fido, str, strlen(str)) < 1)
snprintf(str, sizeof str, "\1FMPT %hu\r"
, hdr->origpoint);
if (write(fido, str, strlen(str)) < 1)
/****************************************************************************/
/* Returns the FidoNet address (struct) parsed from str (in ASCII text). */
/****************************************************************************/
static faddr_t atofaddr(scfg_t* cfg, const char *str)
{
return smb_atofaddr(&cfg->faddr[0], str);
}
/****************************************************************************/
/* Send FidoNet/QWK/Internet NetMail from BBS */
/****************************************************************************/
bool sbbs_t::netmail(const char *into, const char *title, int mode, smb_t* resmb, smbmsg_t* remsg, str_list_t cc_list)
char str[256], fname[128], *buf, *p, ch;
char to[256] = "";
char from[FIDO_NAME_LEN] = "";
char subj[FIDO_SUBJ_LEN] = "";
char msgpath[MAX_PATH + 1];
char tmp[512];
const char* editor = NULL;
const char* charset = NULL;
int file, x;
uint i;
long length, l;
faddr_t src_addr;
faddr_t dest_addr;
uint16_t net_type = NET_NONE;
smbmsg_t msg;
memset(&msg, 0, sizeof(msg));
if (useron.etoday >= cfg.level_emailperday[useron.level] && !SYSOP && !(useron.exempt & FLAG('M'))) {
bputs(text[TooManyEmailsToday]);
if (useron.rest & FLAG('M')) {
bputs(text[NoNetMailAllowed]);
return false;
}
SAFECOPY(subj, title);
SAFECOPY(to, into);
if (remsg != NULL) {
if (subj[0] == 0 && remsg->subj != NULL)
SAFECOPY(subj, remsg->subj);
if (to[0] == 0 && strListCount(cc_list) < 1) {
if ((p = smb_netaddrstr(&remsg->from_net, tmp)) != NULL) {
if (strchr(p, '@')) {
SAFECOPY(to, p);
} else {
SAFEPRINTF2(to, "%s@%s", remsg->from, p);
}
} else {
SAFECOPY(to, remsg->from);
}
}
}
if (*to == '\0' && cc_list != NULL && (*cc_list) != NULL) {
SAFECOPY(to, cc_list[0]);
cc_list++;
}
lookup_netuser(to);
net_type = smb_netaddr_type(to);
lprintf(LOG_DEBUG, "parsed net type of '%s' is %s", to, smb_nettype((enum smb_net_type)net_type));
if (net_type == NET_QWK) {
if (mode & WM_FILE) {
bputs(text[EmailFilesNotAllowed]);
return qnetmail(to, subj, mode, resmb, remsg);
if (net_type == NET_INTERNET) {
if (!(cfg.inetmail_misc & NMAIL_ALLOW)) {
bputs(text[NoNetMailAllowed]);
return false;
}
if (mode & WM_FILE && !SYSOP && !(cfg.inetmail_misc & NMAIL_FILE)) {
bputs(text[EmailFilesNotAllowed]);
return inetmail(to, subj, mode, resmb, remsg, cc_list);
p = strrchr(to, '@'); /* Find '@' in name@addr */
if (p == NULL || net_type != NET_FIDO) {
if (!(sys_status & SS_ABORT))
bprintf(text[InvalidNetMailAddr], to);
if (!cfg.total_faddrs || (!SYSOP && !(cfg.netmail_misc & NMAIL_ALLOW))) {
bputs(text[NoNetMailAllowed]);
*p = 0; /* Chop off address */
p++;
SKIP_WHITESPACE(p);
dest_addr = atofaddr(&cfg, p); /* Get fido address */
if ((mode & WM_FILE) && !SYSOP && !(cfg.netmail_misc & NMAIL_FILE)) {
bputs(text[EmailFilesNotAllowed]);
truncsp(to); /* Truncate off space */
SAFECOPY(from, (cfg.netmail_misc & NMAIL_ALIAS) || (useron.rest & FLAG('O')) ? useron.alias : useron.name);
/* Look-up in nodelist? */
if (cfg.netmail_cost && !(useron.exempt & FLAG('S'))) {
if (user_available_credits(&useron) < cfg.netmail_cost) {
bputs(text[NotEnoughCredits]);
snprintf(str, sizeof str, text[NetMailCostContinueQ], cfg.netmail_cost);
if (noyes(str))
i = nearest_sysfaddr_index(&cfg, &dest_addr);
if ((cfg.netmail_misc & NMAIL_CHSRCADDR) && cfg.total_faddrs > 1) {
for (int j = 0; j < cfg.total_faddrs; j++)
uselect(/* add: */ true, j, text[OriginFidoAddr], smb_faddrtoa(&cfg.faddr[j], tmp), /* ar: */ NULL);
int choice = uselect(/* add: */ false, /* default: */ i, NULL, NULL, NULL);
if (choice < 0)
return false;
i = choice;
}
src_addr = cfg.faddr[i];
smb_faddrtoa(&cfg.faddr[i], str);
bprintf(text[NetMailing], to, smb_faddrtoa(&dest_addr, tmp), from, str);
if (cfg.netmail_misc & NMAIL_CRASH)
msg.hdr.netattr |= NETMSG_CRASH;
if (cfg.netmail_misc & NMAIL_HOLD)
msg.hdr.netattr |= NETMSG_HOLD;
if (cfg.netmail_misc & NMAIL_KILL)
msg.hdr.netattr |= NETMSG_KILLSENT;
if (mode & WM_FILE)
msg.hdr.auxattr |= (MSG_FILEATTACH | MSG_KILLFILE);
if (remsg != NULL && resmb != NULL && !(mode & WM_QUOTE)) {
if (quotemsg(resmb, remsg, /* include tails: */ true))
mode |= WM_QUOTE;
}
msg_tmp_fname(useron.xedit, msgpath, sizeof(msgpath));
if (!writemsg(msgpath, nulstr, subj, WM_NETMAIL | mode, INVALID_SUB, to, from, &editor, &charset)) {
bputs(text[Aborted]);
SAFECOPY(fname, subj);
snprintf(str, sizeof str, "%sfile/%04u.out", cfg.data_dir, useron.number);
SAFECOPY(tmp, cfg.data_dir);
if (tmp[0] == '.') /* Relative path */
snprintf(tmp, sizeof tmp, "%s%s", cfg.node_dir, cfg.data_dir);
SAFEPRINTF3(str, "%sfile/%04u.out/%s", tmp, useron.number, fname);
SAFECOPY(subj, str);
if (fexistcase(str)) {
bprintf(text[FileAlreadyThere], str);
}
{ /* Remote */
char keys[128];
xfer_prot_menu(XFER_UPLOAD, &useron, keys, sizeof keys);
SAFECAT(keys, quit_key(str));
mnemonics(text[ProtocolOrQuit]);
ch = (char)getkeys(keys, 0);
if (ch == quit_key() || sys_status & SS_ABORT) {
bputs(text[Aborted]);
x = protnum(ch, XFER_UPLOAD);
if (x < cfg.total_prots) /* This should be always */
protocol(cfg.prot[x], XFER_UPLOAD, subj, nulstr, true);
snprintf(tmp, sizeof tmp, "%s%s", cfg.temp_dir, subj);
if (!fexistcase(subj) && fexistcase(tmp))
mv(tmp, subj, 0);
l = (long)flength(subj);
if (l > 0)
bprintf(text[FileNBytesReceived], fname, ultoac(l, tmp));
bprintf(text[FileNotReceived], fname);
msg.hdr.netattr |= NETMSG_LOCAL;
lprintf(LOG_DEBUG, "NetMail subject: %s", subj);
p = subj;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "CR:", 3)) { /* Crash over-ride by sysop */
p += 3; /* skip CR: */
SKIP_WHITESPACE(p);
msg.hdr.netattr |= NETMSG_CRASH;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "FR:", 3)) { /* File request */
p += 3; /* skip FR: */
SKIP_WHITESPACE(p);
msg.hdr.auxattr |= MSG_FILEREQUEST;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "RR:", 3)) { /* Return receipt request */
p += 3; /* skip RR: */
SKIP_WHITESPACE(p);
msg.hdr.auxattr |= MSG_RECEIPTREQ;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "FA:", 3)) { /* File Attachment */
p += 3; /* skip FA: */
SKIP_WHITESPACE(p);
// hdr.attr|=FIDO_FILE; TODO
}
SAFECOPY(subj, p);
if ((file = nopen(msgpath, O_RDONLY)) == -1) {
errormsg(WHERE, ERR_OPEN, msgpath, O_RDONLY);
length = (long)filelength(file);
if (length < 0) {
close(file);
errormsg(WHERE, ERR_LEN, msgpath, length);
return false;
}
if ((buf = (char *)calloc(1, length + 1)) == NULL) {
errormsg(WHERE, ERR_ALLOC, str, length);
if (read(file, buf, length) != length) {
errormsg(WHERE, ERR_READ, str, length);
return false;
}
close(file);
smb_net_type_t nettype = NET_FIDO;
smb_hfield_str(&msg, SENDER, from);
snprintf(str, sizeof str, "%u", useron.number);
smb_hfield_str(&msg, SENDEREXT, str);
smb_hfield(&msg, SENDERNETTYPE, sizeof(nettype), &nettype);
smb_hfield(&msg, SENDERNETADDR, sizeof(dest_addr), &src_addr);
smb_hfield_str(&msg, RECIPIENT, to);
smb_hfield(&msg, RECIPIENTNETTYPE, sizeof(nettype), &nettype);
smb_hfield(&msg, RECIPIENTNETADDR, sizeof(dest_addr), &dest_addr);
normalize_msg_hfield_encoding(charset, subj, sizeof subj);
smb_hfield_str(&msg, SUBJECT, subj);
editor_info_to_msg(&msg, editor, charset);
if (cfg.netmail_misc & NMAIL_DIRECT)
msg.hdr.netattr |= NETMSG_DIRECT;
smb_t smb;
memset(&smb, 0, sizeof(smb));
smb.subnum = INVALID_SUB;
int result = savemsg(&cfg, &smb, &msg, &client, server_host_name(), buf, remsg);
free(buf);
smb_close(&smb);
smb_freemsgmem(&msg);
if (result != SMB_SUCCESS) {
errormsg(WHERE, ERR_WRITE, smb.file, result, smb.last_error);
return false;
}
useron.emails = (ushort)adjustuserval(&cfg, useron.number, USER_EMAILS, 1);
useron.etoday = (ushort)adjustuserval(&cfg, useron.number, USER_ETODAY, 1);
if (!(useron.exempt & FLAG('S')))
subtract_cdt(&cfg, &useron, cfg.netmail_cost);
bprintf(text[FidoNetMailSent], to, smb_faddrtoa(&dest_addr, tmp));
if (mode & WM_FILE)
SAFEPRINTF2(str, "sent NetMail file attachment to %s (%s)"
, to, smb_faddrtoa(&dest_addr, tmp));
SAFEPRINTF2(str, "sent NetMail to %s (%s)"
, to, smb_faddrtoa(&dest_addr, tmp));
logline("EN", str);
return true;
}
/****************************************************************************/
/* Send NetMail from QWK REP Packet */
/****************************************************************************/
void sbbs_t::qwktonetmail(FILE *rep, char *block, char *into, uchar fromhub)
{
char * qwkbuf, to[129], name[129], sender[129], senderaddr[129]
, str[256], *p, *cp, *addr, fulladdr[129], ch;
char* sender_id = fromhub ? cfg.qhub[fromhub - 1]->id : useron.alias;
char* subject = NULL;
char tmp[512];
int i, fido, inet = 0, qnet = 0;
uint16_t net;
uint16_t xlat;
long l, length, m, n;
off_t offset;
faddr_t fidoaddr;
fmsghdr_t hdr;
smbmsg_t msg;
struct tm tm;
if (useron.rest & FLAG('M')) {
bputs(text[NoNetMailAllowed]);
to[0] = 0;
name[0] = 0;
sender[0] = 0;
senderaddr[0] = 0;
fulladdr[0] = 0;
snprintf(str, sizeof str, "%.6s", block + 116);
n = atol(str); /* number of 128 byte records */
if (n < 2L || n > 999999L) {
errormsg(WHERE, ERR_CHK, "QWK blocks", n);
return;
}
// Allocate/zero an extra block of NULs for strchr() usage and other ASCIIZ goodness
if ((qwkbuf = (char *)calloc(n + 1, QWK_BLOCK_LEN)) == NULL) {
errormsg(WHERE, ERR_ALLOC, nulstr, n * QWK_BLOCK_LEN);
return;
memcpy((char *)qwkbuf, block, QWK_BLOCK_LEN);
if (fread(qwkbuf + QWK_BLOCK_LEN, QWK_BLOCK_LEN, n - 1, rep) != (size_t)n - 1) {
errormsg(WHERE, ERR_READ, "QWK block", n - 1);
size_t kludge_hdrlen = 0;
char* beg = qwkbuf + QWK_BLOCK_LEN;
char* end = qwkbuf + (n * QWK_BLOCK_LEN);
SAFECOPY(to, p); /* To user on first line */
char* tp = strchr(to, QWK_NEWLINE); /* chop off at first CR */
if (tp != NULL)
*tp = 0;
p += strlen(to) + 1;
}
else
SAFECOPY(to, into);
// Parse QWKE Kludge Lines here:
while (p < end && *p != QWK_NEWLINE) {
if (strncmp(p, "To:", 3) == 0) {
p += 3;
SKIP_WHITESPACE(p);
char* tp = strchr(p, QWK_NEWLINE); /* chop off at first CR */
if (tp != NULL)
*tp = 0;
SAFECOPY(to, p);
p += strlen(p) + 1;
continue;
}
if (strncmp(p, "Subject:", 8) == 0) {
p += 8;
SKIP_WHITESPACE(p);
char* tp = strchr(p, QWK_NEWLINE); /* chop off at first CR */
if (tp != NULL)
*tp = 0;
subject = p;
p += strlen(p) + 1;
continue;
}
break;
}
kludge_hdrlen += (p - beg) + 1;
SAFECOPY(name, to);
p = strchr(name, '@');
truncsp(name);
p = strrchr(to, '@'); /* Find '@' in name@addr */
if (p && !IS_DIGIT(*(p + 1)) && !strchr(p, '.') && !strchr(p, ':')) { /* QWKnet */
qnet = 1;
*p = 0;
else if (p == NULL || !IS_DIGIT(*(p + 1)) || !cfg.total_faddrs) {
if (cfg.inetmail_misc & NMAIL_ALLOW) { /* Internet */
inet = 1;
bprintf(text[InvalidNetMailAddr], to);
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]);
free(qwkbuf);
truncsp(to); /* Truncate off space */
if (!stricmp(to, "SBBS") && !SYSOP && qnet) {
l = QWK_BLOCK_LEN + kludge_hdrlen; /* Start of message text */
memset(&msg, 0, sizeof(smbmsg_t));
msg.hdr.version = smb_ver();
msg.hdr.when_imported.time = time32(NULL);
msg.hdr.when_imported.zone = sys_timezone(&cfg);
if (fromhub || useron.rest & FLAG('Q')) {
net = NET_QWK;
smb_hfield(&msg, SENDERNETTYPE, sizeof(net), &net);
if (!strncmp(qwkbuf + l, "@VIA:", 5)) {
snprintf(str, sizeof str, "%.128s", qwkbuf + l + 5);
cp = strchr(str, QWK_NEWLINE);
l += strlen(str) + 1;
cp = str;
while (*cp && *cp <= ' ') cp++;
safe_snprintf(senderaddr, sizeof(senderaddr), "%s/%s", sender_id, cp);
strupr(senderaddr);
smb_hfield(&msg, SENDERNETADDR, strlen(senderaddr), senderaddr);
}
else {
SAFECOPY(senderaddr, sender_id);
strupr(senderaddr);
smb_hfield(&msg, SENDERNETADDR, strlen(senderaddr), senderaddr);
snprintf(sender, sizeof sender, "%.25s", block + 46); /* From name */
}
else { /* Not Networked */
msg.hdr.when_written.zone = sys_timezone(&cfg);
snprintf(str, sizeof str, "%u", useron.number);
smb_hfield(&msg, SENDEREXT, strlen(str), str);
SAFECOPY(sender, (qnet || cfg.inetmail_misc & NMAIL_ALIAS)
? useron.alias : useron.name);
}
truncsp(sender);
smb_hfield(&msg, SENDER, strlen(sender), sender);
if (fromhub)
msg.idx.from = 0;
msg.idx.from = useron.number;
if (!strncmp(qwkbuf + l, "@TZ:", 4)) {
snprintf(str, sizeof str, "%.128s", qwkbuf + l);
cp = strchr(str, QWK_NEWLINE);
l += strlen(str) + 1;
cp = str + 4;
while (*cp && *cp <= ' ') cp++;
msg.hdr.when_written.zone = (short)ahtoul(cp);
msg.hdr.when_written.zone = sys_timezone(&cfg);
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;
tm.tm_isdst = -1; /* Do not adjust for DST */
msg.hdr.when_written = smb_when(mktime(&tm), msg.hdr.when_written.zone);
if (subject == NULL) {
snprintf(str, sizeof str, "%.25s", block + 71);
subject = str;
}
smb_hfield_str(&msg, SUBJECT, subject);
}
addr = p;
msg.idx.to = qwk_route(&cfg, addr, fulladdr, sizeof(fulladdr) - 1);
if (!fulladdr[0]) { /* Invalid address, so BOUNCE it */
/**
errormsg(WHERE,ERR_CHK,addr,0);
free(qwkbuf);
smb_freemsgmem(msg);
return;
**/
smb_hfield(&msg, SENDER, strlen(cfg.sys_id), cfg.sys_id);
msg.idx.from = 0;
msg.idx.to = useron.number;
SAFECOPY(to, sender);
SAFECOPY(fulladdr, senderaddr);
SAFEPRINTF(str, "BADADDR: %s", addr);
smb_hfield(&msg, SUBJECT, strlen(str), str);
net = NET_NONE;
smb_hfield(&msg, SENDERNETTYPE, sizeof(net), &net);
}
/* This is required for fixsmb to be able to rebuild the index */
SAFEPRINTF(str, "%u", msg.idx.to);
smb_hfield_str(&msg, RECIPIENTEXT, str);
smb_hfield(&msg, RECIPIENT, strlen(name), name);
net = NET_QWK;
smb_hfield(&msg, RECIPIENTNETTYPE, sizeof(net), &net);
truncsp(fulladdr);
if (fulladdr[0])
smb_hfield(&msg, RECIPIENTNETADDR, strlen(fulladdr), fulladdr);
bprintf(text[NetMailing], to, fulladdr, sender, cfg.sys_id);
if (inet) { /* Internet E-mail */
if (cfg.inetmail_cost && !(useron.exempt & FLAG('S'))) {
if (user_available_credits(&useron) < cfg.inetmail_cost) {
bputs(text[NotEnoughCredits]);
free(qwkbuf);
smb_freemsgmem(&msg);
snprintf(str, sizeof str, text[NetMailCostContinueQ], cfg.inetmail_cost);
if (noyes(str)) {
free(qwkbuf);
smb_freemsgmem(&msg);
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.rest & FLAG('O')) ? useron.alias : useron.name
, cfg.sys_inetaddr);
bputs(text[WritingIndx]);
if ((i = smb_stack(&smb, SMB_STACK_PUSH)) != 0) {
errormsg(WHERE, ERR_OPEN, "MAIL", i);
free(qwkbuf);
smb_freemsgmem(&msg);
snprintf(smb.file, sizeof smb.file, "%smail", cfg.data_dir);
smb.retry_time = cfg.smb_retry_time;
smb.subnum = INVALID_SUB;
if ((i = smb_open(&smb)) != 0) {
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_OPEN, smb.file, i, smb.last_error);
free(qwkbuf);
smb_freemsgmem(&msg);
add_msg_ids(&cfg, &smb, &msg, /* remsg: */ NULL);
if (smb_fgetlength(smb.shd_fp) < 1L) { /* Create it if it doesn't exist */
smb.status.max_crcs = cfg.mail_maxcrcs;
smb.status.max_msgs = 0;
smb.status.max_age = cfg.mail_maxage;
smb.status.attr = SMB_EMAIL;
if ((i = smb_create(&smb)) != 0) {
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_CREATE, smb.file, i, smb.last_error);
free(qwkbuf);
smb_freemsgmem(&msg);
length = n * 256L; // Extra big for CRLF xlat, was (n-1L)*256L (03/16/96)
if (length & 0xfff00000UL || !length) {
smb_stack(&smb, SMB_STACK_POP);
snprintf(str, sizeof str, "REP msg (%ld)", n);
errormsg(WHERE, ERR_LEN, str, length);
free(qwkbuf);
smb_freemsgmem(&msg);
if ((i = smb_open_da(&smb)) != 0) {
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_OPEN, smb.file, i, smb.last_error);
free(qwkbuf);
smb_freemsgmem(&msg);
if (cfg.sys_misc & SM_FASTMAIL)
offset = smb_fallocdat(&smb, length, 1);
offset = smb_allocdat(&smb, length, 1);
smb_close_da(&smb);
smb_fseek(smb.sdt_fp, offset, SEEK_SET);
xlat = XLAT_NONE;
smb_fwrite(&smb, &xlat, 2, smb.sdt_fp);
m = 2;
for (; l < n * QWK_BLOCK_LEN && m < length; l++) {
if (qwkbuf[l] == 0 || qwkbuf[l] == LF)
if (qwkbuf[l] == QWK_NEWLINE) {
if (m <= 2) /* Ignore blank lines at top of message */
smb_fwrite(&smb, crlf, 2, smb.sdt_fp);
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 = (uint32_t)offset;
smb_dfield(&msg, TEXT_BODY, length);
i = smb_addmsghdr(&smb, &msg, smb_storage_mode(&cfg, &smb));
smb_stack(&smb, SMB_STACK_POP);
smb_freemsgmem(&msg);
if (i != SMB_SUCCESS) {
errormsg(WHERE, ERR_WRITE, smb.file, i, smb.last_error);
smb_freemsgdat(&smb, offset, length, 1);
else { /* Successful */
if (inet) {
if (cfg.inetmail_sem[0]) /* update semaphore file */
ftouch(cmdstr(cfg.inetmail_sem, nulstr, nulstr, NULL));
if (!(useron.exempt & FLAG('S')))
subtract_cdt(&cfg, &useron, cfg.inetmail_cost);
useron.emails = (ushort)adjustuserval(&cfg, useron.number, USER_EMAILS, 1);
useron.etoday = (ushort)adjustuserval(&cfg, useron.number, USER_ETODAY, 1);
bprintf(text[QWKNetMailSent], name, fulladdr);
else
bprintf(text[InternetMailSent], name, to);
safe_snprintf(str, sizeof(str), "%s (%s) sent %s NetMail to %s (%s) via QWK"
, sender, sender_id
, qnet ? "QWK":"Internet", name, qnet ? fulladdr : to);
logline("EN", str);
}
free((char *)qwkbuf);
}
/****************************** FidoNet **********************************/
if (!fidoaddr.zone || !cfg.netmail_dir[0]) { // No fido netmail allowed
bprintf(text[InvalidNetMailAddr], to);
memset(&hdr, 0, sizeof(hdr)); /* Initialize header to null */
if (fromhub || useron.rest & FLAG('Q')) {
snprintf(str, sizeof str, "%.25s", block + 46); /* From */
snprintf(tmp, sizeof tmp, "@%s", sender_id);
SAFECOPY(str, (cfg.netmail_misc & NMAIL_ALIAS) || (useron.rest & FLAG('O')) ? useron.alias : useron.name);
SAFECOPY(hdr.from, str);
/* Look-up in nodelist? */
if (cfg.netmail_cost && !(useron.exempt & FLAG('S'))) {
if (user_available_credits(&useron) < cfg.netmail_cost) {
bputs(text[NotEnoughCredits]);
free(qwkbuf);
snprintf(str, sizeof str, text[NetMailCostContinueQ], cfg.netmail_cost);
if (noyes(str)) {
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)
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;
smb_faddrtoa(&cfg.faddr[i], str);
bprintf(text[NetMailing], hdr.to, smb_faddrtoa(&fidoaddr, tmp), hdr.from, str);
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;
safe_snprintf(hdr.time, sizeof(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;
snprintf(str, sizeof str, "%.25s", block + 71); /* Title */
p = str;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "CR:", 3)) { /* Crash over-ride by sysop */
p += 3; /* skip CR: */
if (*p == ' ')
p++; /* skip extra space if it exists */
hdr.attr |= FIDO_CRASH;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "FR:", 3)) { /* File request */
p += 3; /* skip FR: */
hdr.attr |= FIDO_FREQ;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "RR:", 3)) { /* Return receipt request */
p += 3; /* skip RR: */
hdr.attr |= FIDO_RRREQ;
if ((SYSOP || useron.exempt & FLAG('F'))
&& !strnicmp(p, "FA:", 3)) { /* File attachment */
p += 3; /* skip FA: */
hdr.attr |= FIDO_FILE;
SAFECOPY(hdr.subj, subject);
else
SAFECOPY(hdr.subj, p);
md(cfg.netmail_dir);
for (i = 1; i; i++) {
snprintf(str, sizeof str, "%s%u.msg", cfg.netmail_dir, i);
if (!fexistcase(str))
break;
bputs(text[TooManyEmailsToday]);
if ((fido = nopen(str, O_WRONLY | O_CREAT | O_EXCL)) == -1) {
errormsg(WHERE, ERR_OPEN, str, O_WRONLY | O_CREAT | O_EXCL);
return;
if (write(fido, &hdr, sizeof(hdr)) != sizeof hdr) {
free(qwkbuf);
errormsg(WHERE, ERR_WRITE, str, sizeof hdr);
return;
}
pt_zone_kludge(&hdr, fido);
if (cfg.netmail_misc & NMAIL_DIRECT) {
snprintf(str, sizeof str, "\1FLAGS DIR\r\n");
if (write(fido, str, strlen(str)) < 1)
errormsg(WHERE, ERR_WRITE, str, 0);
}
l = QWK_BLOCK_LEN + kludge_hdrlen;
length = n * QWK_BLOCK_LEN;
while (l < length) {
if (qwkbuf[l] == CTRL_A) { /* Ctrl-A, so skip it and the next char */
else if (qwkbuf[l] != LF) {
if (qwkbuf[l] == QWK_NEWLINE) /* QWK cr/lf char converted to hard CR */
qwkbuf[l] = CR;
if (write(fido, (char *)qwkbuf + l, 1) != 1)
errormsg(WHERE, ERR_WRITE, "fidonet netmail", 1);
l = 0;
if (write(fido, (BYTE*)&l, sizeof(BYTE)) != sizeof(BYTE)) /* Null terminator */
errormsg(WHERE, ERR_WRITE, "fidonet netmail", sizeof(BYTE));
close(fido);
free((char *)qwkbuf);
if (cfg.netmail_sem[0]) /* update semaphore file */
ftouch(cmdstr(cfg.netmail_sem, nulstr, nulstr, NULL));
if (!(useron.exempt & FLAG('S')))
subtract_cdt(&cfg, &useron, cfg.netmail_cost);
useron.emails = (ushort)adjustuserval(&cfg, useron.number, USER_EMAILS, 1);
useron.etoday = (ushort)adjustuserval(&cfg, useron.number, USER_ETODAY, 1);
bprintf(text[FidoNetMailSent], hdr.to, smb_faddrtoa(&fidoaddr, tmp));
snprintf(str, sizeof str, "%s sent NetMail to %s @%s via QWK"
, sender_id
, hdr.to, smb_faddrtoa(&fidoaddr, tmp));
logline("EN", str);
/****************************************************************************/
/* Internet mail */
/****************************************************************************/
bool sbbs_t::inetmail(const char *into, const char *subj, int mode, smb_t* resmb, smbmsg_t* remsg, str_list_t cc_list)
char str[256], str2[256], msgpath[256], ch, *p;
char tmp[512];
char title[256] = "";
char name[256] = "";
char addr[256] = "";
const char* editor = NULL;
const char* charset = NULL;
char your_addr[128];
int i, x, file;
long l;
FILE * instream;
smbmsg_t msg;
if ((!SYSOP && !(cfg.inetmail_misc & NMAIL_ALLOW)) || useron.rest & FLAG('M')) {
bputs(text[NoNetMailAllowed]);
return false;
}
str_list_t rcpt_list = strListInit();
if (into != NULL && *into)
for (i = 0; cc_list != NULL && cc_list[i] != NULL; i++) {
char* p = cc_list[i];
char* at = strchr(p, '@');
bprintf(text[InvalidNetMailAddr], p);
continue;
}
while (at > p && *at > ' ')
at--;
p = at;
SKIP_WHITESPACE(p);
uint16_t net_type = smb_netaddr_type(p);
if (net_type != NET_INTERNET) {
bprintf(text[InvalidNetMailAddr], p);
break;
}
strListPush(&rcpt_list, p);
strListStripStrings(rcpt_list, "<>");
size_t rcpt_count = strListDedupe(&rcpt_list, /* case-sensitive */ false);
if (useron.etoday + rcpt_count > cfg.level_emailperday[useron.level] && !SYSOP && !(useron.exempt & FLAG('M'))) {
strListFree(&rcpt_list);
bputs(text[TooManyEmailsToday]);
if (subj != NULL)
SAFECOPY(title, subj);
if (remsg != NULL) {
if (title[0] == 0 && remsg->subj != NULL)
SAFECOPY(title, remsg->subj);
if (remsg->from_net.addr != NULL && rcpt_count < 1) {