Newer
Older
/* Synchronet email function - for sending private e-mail */
/****************************************************************************
* @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 "cmdshell.h"
/****************************************************************************/
/* Mails a message to usernumber. 'top' is a buffer to place at beginning */
/* of message. */
/* Called from functions main_sec, newuser, readmail and scanposts */
/****************************************************************************/
bool sbbs_t::email(int usernumber, const char *top, const char *subj, int mode, smb_t* resmb, smbmsg_t* remsg)
char str[256], str2[256], msgpath[256], ch
, buf[SDT_BLOCK_LEN];
char keys[128];
char tmp[512];
char title[LEN_TITLE + 1] = "";
const char* editor = NULL;
const char* charset = NULL;
uint16_t msgattr = 0;
uint16_t xlat = XLAT_NONE;
int i, j, x, file;
int length;
off_t offset;
uint32_t crc = 0xffffffffUL;
FILE* instream;
node_t node;
user_t user{};
smbmsg_t msg;
if (subj != NULL)
if (remsg != NULL && title[0] == 0)
if (useron.etoday >= cfg.level_emailperday[useron.level] && !SYSOP && !(useron.exempt & FLAG('M'))) {
bputs(text[TooManyEmailsToday]);
if (getuserdat(&cfg, &user) != 0 || (user.misc & (DELETED | INACTIVE))) {
bool to_sysop = user_is_sysop(&user);
if (to_sysop && useron.rest & FLAG('S')
&& (cfg.valuser != usernumber || useron.fbacks || useron.emails)) { /* ! val fback */
bprintf(text[R_Feedback], cfg.sys_op);
if (!to_sysop && useron.rest & FLAG('E')
&& (cfg.valuser != usernumber || useron.fbacks || useron.emails)) {
if ((user.misc & NETMAIL) && (cfg.sys_misc & SM_FWDTONET) && !(mode & WM_NOFWD) && !(useron.rest & FLAG('M'))) {
if (is_supported_netmail_addr(&cfg, user.netmail)) {
bprintf(text[UserNetMail], user.netmail);
if ((mode & WM_FORCEFWD) || yesno(text[ForwardMailQ])) /* Forward to netmail address */
return netmail(user.netmail, subj, mode, resmb, remsg);
bprintf(text[InvalidNetMailAddr], user.netmail);
}
if (sys_status & SS_ABORT) {
bputs(text[Aborted]);
return false;
}
bprintf(text[Emailing], username(&cfg, usernumber, tmp), usernumber);
action = NODE_SMAL;
if (cfg.feedback_mod[0] && to_sysop && !SYSOP
&& (useron.fbacks || usernumber != cfg.valuser)) {
if (exec_bin(cfg.feedback_mod, &main_csi) != 0 || main_csi.logic != LOGIC_TRUE)
if (cfg.sys_misc & SM_ANON_EM && useron.exempt & FLAG('A')
&& !noyes(text[AnonymousQ])) {
msgattr |= MSG_ANONYMOUS;
mode |= WM_ANON;
if (cfg.sys_misc & SM_DELREADM)
msgattr |= MSG_KILLREAD;
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));
username(&cfg, usernumber, str2);
if (!writemsg(msgpath, top, /* subj: */ title, WM_EMAIL | mode, INVALID_SUB, /* to: */ str2, /* from: */ useron.alias, &editor, &charset)) {
}
if (mode & WM_FILE && !SYSOP && !(cfg.sys_misc & SM_FILE_EM)) {
bputs(text[EmailFilesNotAllowed]);
}
if (mode & WM_FILE) {
if (!checkfname(title)) {
bprintf(text[BadFilename], title);
}
SAFEPRINTF2(str2, "%sfile/%04u.in", cfg.data_dir, usernumber);
SAFEPRINTF3(str2, "%sfile/%04u.in/%s", cfg.data_dir, usernumber, title);
if (fexistcase(str2)) {
bprintf(text[FileAlreadyThere], str2);
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, str2, nulstr, true);
safe_snprintf(tmp, sizeof(tmp), "%s%s", cfg.temp_dir, title);
if (!fexistcase(str2) && fexistcase(tmp))
mv(tmp, str2, 0);
off_t l = flength(str2);
if (l > 0)
bprintf(text[FileNBytesReceived], title, u64toac(l, tmp));
bprintf(text[FileNotReceived], title);
bputs(text[WritingIndx]);
if ((i = smb_stack(&smb, SMB_STACK_PUSH)) != 0) {
errormsg(WHERE, ERR_OPEN, "MAIL", i);
if ((i = smb_open_sub(&cfg, &smb, INVALID_SUB)) != 0) {
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_OPEN, smb.file, i, smb.last_error);
if ((i = smb_locksmbhdr(&smb)) != 0) {
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_LOCK, smb.file, i, smb.last_error);
length = (int)flength(msgpath) + 2; /* +2 for translation string */
if (length & 0xfff00000UL) {
smb_unlocksmbhdr(&smb);
smb_close(&smb);
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_LEN, msgpath, length);
if ((i = smb_open_da(&smb)) != 0) {
smb_unlocksmbhdr(&smb);
smb_close(&smb);
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_OPEN, smb.file, i, smb.last_error);
if (cfg.sys_misc & SM_FASTMAIL)
offset = smb_fallocdat(&smb, length, 1);
offset = smb_allocdat(&smb, length, 1);
if ((instream = fnopen(&file, msgpath, O_RDONLY | O_BINARY)) == NULL) {
smb_freemsgdat(&smb, offset, length, 1);
smb_unlocksmbhdr(&smb);
smb_close(&smb);
smb_stack(&smb, SMB_STACK_POP);
errormsg(WHERE, ERR_OPEN, msgpath, O_RDONLY | O_BINARY);
smb_fseek(smb.sdt_fp, offset, SEEK_SET);
xlat = XLAT_NONE;
smb_fwrite(&smb, &xlat, 2, smb.sdt_fp);
x = SDT_BLOCK_LEN - 2; /* Don't read/write more than 255 */
while (!feof(instream)) {
memset(buf, 0, x);
j = fread(buf, 1, x, instream);
if (j < 1)
if (j > 1 && (j != x || feof(instream)) && buf[j - 1] == LF && buf[j - 2] == CR)
buf[j - 1] = buf[j - 2] = 0;
if (cfg.mail_maxcrcs) {
for (i = 0; i < j; i++)
crc = ucrc32(buf[i], crc);
smb_fwrite(&smb, buf, j, smb.sdt_fp);
x = SDT_BLOCK_LEN;
smb_fflush(smb.sdt_fp);
fclose(instream);
memset(&msg, 0, sizeof(smbmsg_t));
msg.hdr.version = smb_ver();
msg.hdr.attr = msgattr;
if (mode & WM_FILE)
msg.hdr.auxattr |= (MSG_FILEATTACH | MSG_KILLFILE);
msg.hdr.when_imported.time = time32(NULL);
msg.hdr.when_imported.zone = sys_timezone(&cfg);
msg.hdr.when_written = smb_when(msg.hdr.when_imported.time, msg.hdr.when_imported.zone);
if (cfg.mail_maxcrcs) {
i = smb_addcrc(&smb, crc);
if (i) {
smb_freemsgdat(&smb, offset, length, 1);
smb_unlocksmbhdr(&smb);
smb_close(&smb);
smb_stack(&smb, SMB_STACK_POP);

Rob Swindell
committed
bprintf(text[CantPostMsg], i == SMB_DUPE_MSG ? "duplicate" : "other");
msg.hdr.offset = (uint32_t)offset;
username(&cfg, usernumber, str);
smb_hfield_str(&msg, RECIPIENT, str);
SAFEPRINTF(str, "%u", usernumber);
smb_hfield_str(&msg, RECIPIENTEXT, str);
SAFECOPY(str, useron.alias);
smb_hfield_str(&msg, SENDER, str);
SAFEPRINTF(str, "%u", useron.number);
smb_hfield_str(&msg, SENDEREXT, str);
if (useron.misc & NETMAIL) {
if (useron.rest & FLAG('G'))
smb_hfield_str(&msg, REPLYTO, useron.name);
smb_hfield_netaddr(&msg, REPLYTONETADDR, useron.netmail, NULL);
}
/* Security logging */
msg_client_hfields(&msg, &client);
smb_hfield_str(&msg, SENDERSERVER, server_host_name());
normalize_msg_hfield_encoding(charset, title, sizeof title);
smb_hfield_str(&msg, SUBJECT, title);
add_msg_ids(&cfg, &smb, &msg, remsg);
editor_info_to_msg(&msg, editor, charset);
smb_dfield(&msg, TEXT_BODY, length);
i = smb_addmsghdr(&smb, &msg, smb_storage_mode(&cfg, &smb)); // calls smb_unlocksmbhdr()
if (i == SMB_SUCCESS && remsg != NULL)
smb_updatethread(&smb, remsg, msg.hdr.number);
smb_stack(&smb, SMB_STACK_POP);
if (i != SMB_SUCCESS) {
smb_freemsgdat(&smb, offset, length, 1);
errormsg(WHERE, ERR_WRITE, smb.file, i, smb.last_error);
else
user_sent_email(&cfg, &useron, 1, usernumber == 1);
bprintf(text[Emailed], username(&cfg, usernumber, tmp), usernumber);
safe_snprintf(str, sizeof(str), "sent e-mail to %s #%d"
, username(&cfg, usernumber, tmp), usernumber);
logline("E+", str);
if (mode & WM_FILE && online == ON_REMOTE)
if (msgattr & MSG_ANONYMOUS) /* Don't tell user if anonymous */
for (i = 1; i <= cfg.sys_nodes; i++) { /* Tell user, if online */
getnodedat(i, &node);
if (node.useron == usernumber && !(node.misc & NODE_POFF)
&& (node.status == NODE_INUSE || node.status == NODE_QUIET)) {
safe_snprintf(str, sizeof(str), text[EmailNodeMsg], cfg.node_num, useron.alias);
putnmsg(i, str);
break;
}
if (i > cfg.sys_nodes) { /* User wasn't online, so leave short msg */
safe_snprintf(str, sizeof(str), text[UserSentYouMail], useron.alias);
putsmsg(usernumber, str);