This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
magicka/src/bluewave.c

1144 lines
29 KiB
C
Raw Normal View History

2016-12-06 17:06:28 +10:00
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <termios.h>
#include <fcntl.h>
2018-01-08 08:54:03 +10:00
#include <sqlite3.h>
#include <sys/wait.h>
2016-12-06 17:06:28 +10:00
#include "jamlib/jam.h"
2018-05-22 21:02:22 +10:00
#include "libuuid/uuid.h"
2016-12-06 17:06:28 +10:00
#include "bluewave.h"
#include "bbs.h"
#include "mail_utils.h"
2016-12-06 17:06:28 +10:00
extern struct bbs_config conf;
extern struct user_record *gUser;
extern int mynode;
extern char upload_filename[1024];
extern int sshBBS;
2016-12-11 22:14:36 +10:00
extern int bbs_stdin;
extern int bbs_stdout;
extern int bbs_stderr;
2016-12-06 17:06:28 +10:00
tLONG convertl(tLONG l) {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
unsigned char result_bytes[4];
unsigned int result;
result_bytes[0] = (unsigned char)((l >> 24) & 0xFF);
result_bytes[1] = (unsigned char)((l >> 16) & 0xFF);
result_bytes[2] = (unsigned char)((l >> 8) & 0xFF);
result_bytes[3] = (unsigned char)(l & 0xFF);
2016-12-06 17:06:28 +10:00
memcpy(&result, result_bytes, 4);
return result;
#else
return l;
#endif
}
tWORD converts(tWORD s) {
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
unsigned char result_bytes[2];
unsigned short result;
result_bytes[0] = (unsigned char)((s >> 8) & 0xFF);
result_bytes[1] = (unsigned char)(s & 0xFF);
2016-12-06 17:06:28 +10:00
memcpy(&result, result_bytes, 4);
return result;
#else
return s;
#endif
}
2018-01-08 08:54:03 +10:00
int bwave_scan_email(int areano, int totmsgs, FILE *fti_file, FILE *mix_file, FILE *dat_file, int *last_ptr) {
sqlite3 *db;
sqlite3_stmt *res;
int rc;
char *sql = "SELECT sender,subject,date,body,id FROM email WHERE recipient LIKE ? AND seen = 0";
char *sqlseen = "UPDATE email SET seen = 1 WHERE recipient LIKE ?";
2018-01-08 08:54:03 +10:00
char buffer[PATH_MAX];
MIX_REC mix;
FTI_REC fti;
long mixptr;
struct tm timeStruct;
char *month_name[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
time_t thetime;
char *body;
int area_msgs = 0;
snprintf(buffer, PATH_MAX, "%s/email.sq3", conf.bbs_path);
rc = sqlite3_open(buffer, &db);
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
2018-01-08 08:54:03 +10:00
return totmsgs;
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_prepare_v2(db, sql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, gUser->loginname, -1, 0);
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
return totmsgs;
}
mixptr = ftell(fti_file);
while (sqlite3_step(res) == SQLITE_ROW) {
memset(&fti, 0, sizeof(FTI_REC));
strlcpy(fti.from, sqlite3_column_text(res, 0), sizeof fti.from);
strlcpy(fti.to, gUser->loginname, sizeof fti.to);
strlcpy(fti.subject, sqlite3_column_text(res, 1), sizeof fti.subject);
2018-01-08 08:54:03 +10:00
thetime = sqlite3_column_int(res, 2);
localtime_r((time_t *)&thetime, &timeStruct);
snprintf(fti.date, sizeof fti.date, "%02d-%s-%04d %02d:%02d", timeStruct.tm_mday, month_name[timeStruct.tm_mon], timeStruct.tm_year + 1900, timeStruct.tm_hour, timeStruct.tm_min);
2018-01-08 08:54:03 +10:00
fti.msgnum = converts((tWORD)sqlite3_column_int(res, 4));
body = strdup(sqlite3_column_text(res, 3));
fti.replyto = 0;
fti.replyat = 0;
fti.msgptr = convertl(*last_ptr);
fti.msglength = convertl(strlen(body));
*last_ptr += strlen(body);
2018-01-08 08:54:03 +10:00
fti.flags |= FTI_MSGLOCAL;
fti.flags = converts(fti.flags);
fti.orig_zone = 0;
fti.orig_net = 0;
fti.orig_node = 0;
fwrite(body, 1, strlen(body), dat_file);
fwrite(&fti, sizeof(FTI_REC), 1, fti_file);
free(body);
area_msgs++;
totmsgs++;
2018-01-08 08:54:03 +10:00
}
sqlite3_finalize(res);
2018-01-08 09:59:20 +10:00
rc = sqlite3_prepare_v2(db, sqlseen, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, gUser->loginname, -1, 0);
sqlite3_step(res);
}
2018-01-08 08:54:03 +10:00
sqlite3_finalize(res);
sqlite3_close(db);
memset(&mix, 0, sizeof(MIX_REC));
2018-01-08 08:54:03 +10:00
snprintf(mix.areanum, 6, "%d", 1);
mix.totmsgs = converts(area_msgs);
mix.numpers = converts(area_msgs);
mix.msghptr = convertl(mixptr);
fwrite(&mix, sizeof(MIX_REC), 1, mix_file);
2018-01-08 08:54:03 +10:00
return totmsgs;
}
2016-12-06 17:06:28 +10:00
int bwave_scan_area(int confr, int area, int areano, int totmsgs, FILE *fti_file, FILE *mix_file, FILE *dat_file, int *last_ptr) {
2018-02-18 13:51:39 +10:00
struct msg_headers *msghs = read_message_headers(confr, area, gUser, 0);
2016-12-06 17:06:28 +10:00
int all_unread = 1;
s_JamBase *jb;
s_JamLastRead jlr;
int i;
int k;
MIX_REC mix;
int area_msgs;
int personal_msgs;
long mixptr;
FTI_REC fti;
struct fido_addr *fido;
char *body;
struct tm timeStruct;
char realname[66];
2016-12-06 17:06:28 +10:00
char *month_name[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
snprintf(realname, 65, "%s %s", gUser->firstname, gUser->lastname);
2016-12-06 17:06:28 +10:00
if (msghs == NULL) {
return totmsgs;
}
struct mail_area *ma = get_area(confr, area);
jb = open_jam_base(ma->path);
2016-12-06 17:06:28 +10:00
if (!jb) {
dolog("Error opening JAM base.. %s", ma->path);
2016-12-07 09:24:15 +10:00
if (msghs != NULL) {
free_message_headers(msghs);
}
2016-12-06 17:06:28 +10:00
return totmsgs;
}
all_unread = 0;
if (JAM_ReadLastRead(jb, gUser->id, &jlr) == JAM_NO_USER) {
jlr.LastReadMsg = 0;
jlr.HighReadMsg = 0;
jlr.UserCRC = JAM_Crc32(gUser->loginname, strlen(gUser->loginname));
jlr.UserID = gUser->id;
all_unread = 1;
} else if (jlr.LastReadMsg == 0 && jlr.HighReadMsg == 0) {
all_unread = 1;
2016-12-06 17:06:28 +10:00
}
2016-12-06 17:06:28 +10:00
if (all_unread == 0) {
k = jlr.HighReadMsg;
for (i = 0; i < msghs->msg_count; i++) {
2016-12-06 17:06:28 +10:00
if (msghs->msgs[i]->msg_h->MsgNum == k) {
break;
}
}
i += 1;
2016-12-06 17:06:28 +10:00
} else {
i = 0;
}
2016-12-06 17:06:28 +10:00
mixptr = ftell(fti_file);
area_msgs = 0;
personal_msgs = 0;
for (k = i; k < msghs->msg_count; k++) {
2016-12-06 17:06:28 +10:00
if (totmsgs == conf.bwave_max_msgs) {
break;
}
2016-12-11 22:14:36 +10:00
if (msghs->msgs[k]->to != NULL) {
if (strcasecmp(msghs->msgs[k]->to, gUser->loginname) == 0 || strncasecmp(msghs->msgs[k]->to, realname, 42) == 0) {
2016-12-11 22:14:36 +10:00
personal_msgs++;
}
2016-12-06 17:06:28 +10:00
}
2016-12-06 17:06:28 +10:00
memset(&fti, 0, sizeof(FTI_REC));
2016-12-11 22:14:36 +10:00
if (msghs->msgs[k]->from != NULL) {
strlcpy(fti.from, msghs->msgs[k]->from, sizeof fti.from);
2016-12-11 22:14:36 +10:00
} else {
strlcpy(fti.from, "(Missing From)", sizeof fti.from);
2016-12-11 22:14:36 +10:00
}
if (msghs->msgs[k]->to != NULL) {
strlcpy(fti.to, msghs->msgs[k]->to, sizeof fti.to);
2016-12-11 22:14:36 +10:00
} else {
2018-10-15 10:31:28 +10:00
strlcpy(fti.to, "(Missing To)", sizeof fti.to);
2016-12-11 22:14:36 +10:00
}
2016-12-11 22:14:36 +10:00
if (msghs->msgs[k]->subject != NULL) {
2018-10-15 10:31:28 +10:00
strlcpy(fti.subject, msghs->msgs[k]->subject, sizeof fti.subject);
2016-12-11 22:14:36 +10:00
} else {
strlcpy(fti.subject, "(Missing Subject)", sizeof fti.subject);
2016-12-11 22:14:36 +10:00
}
2016-12-06 17:06:28 +10:00
localtime_r((time_t *)&msghs->msgs[k]->msg_h->DateWritten, &timeStruct);
snprintf(fti.date, sizeof fti.date, "%02d-%s-%04d %02d:%02d", timeStruct.tm_mday, month_name[timeStruct.tm_mon], timeStruct.tm_year + 1900, timeStruct.tm_hour, timeStruct.tm_min);
2016-12-06 17:06:28 +10:00
fti.msgnum = converts((tWORD)msghs->msgs[k]->msg_h->MsgNum);
fti.replyto = 0;
fti.replyat = 0;
fti.msgptr = convertl(*last_ptr);
2016-12-06 17:06:28 +10:00
fti.msglength = convertl(msghs->msgs[k]->msg_h->TxtLen);
*last_ptr += msghs->msgs[k]->msg_h->TxtLen;
if (msghs->msgs[k]->msg_h->Attribute & JAM_MSG_LOCAL) {
2016-12-06 17:06:28 +10:00
fti.flags |= FTI_MSGLOCAL;
}
2016-12-06 17:06:28 +10:00
fti.flags = converts(fti.flags);
2016-12-06 17:06:28 +10:00
fido = parse_fido_addr(msghs->msgs[k]->oaddress);
if (fido != NULL) {
fti.orig_zone = converts(fido->zone);
fti.orig_net = converts(fido->net);
fti.orig_node = converts(fido->node);
free(fido);
} else {
fti.orig_zone = 0;
fti.orig_net = 0;
fti.orig_node = 0;
}
// write msg data
body = (char *)malloz(msghs->msgs[k]->msg_h->TxtLen);
JAM_ReadMsgText(jb, msghs->msgs[k]->msg_h->TxtOffset, msghs->msgs[k]->msg_h->TxtLen, body);
2016-12-06 17:06:28 +10:00
fwrite(body, 1, msghs->msgs[k]->msg_h->TxtLen, dat_file);
fwrite(&fti, sizeof(FTI_REC), 1, fti_file);
2016-12-06 17:06:28 +10:00
free(body);
jlr.LastReadMsg = msghs->msgs[k]->msg_h->MsgNum;
if (jlr.HighReadMsg < msghs->msgs[k]->msg_h->MsgNum) {
jlr.HighReadMsg = msghs->msgs[k]->msg_h->MsgNum;
}
2016-12-06 17:06:28 +10:00
JAM_WriteLastRead(jb, gUser->id, &jlr);
2016-12-06 17:06:28 +10:00
area_msgs++;
totmsgs++;
}
2017-09-21 21:45:24 +10:00
//if (area_msgs) {
memset(&mix, 0, sizeof(MIX_REC));
snprintf(mix.areanum, 6, "%d", areano);
mix.totmsgs = converts(area_msgs);
mix.numpers = converts(personal_msgs);
mix.msghptr = convertl(mixptr);
fwrite(&mix, sizeof(MIX_REC), 1, mix_file);
2017-09-21 21:45:24 +10:00
//}
2016-12-06 17:06:28 +10:00
JAM_CloseMB(jb);
2018-02-10 16:01:30 +10:00
free(jb);
2016-12-06 17:06:28 +10:00
free_message_headers(msghs);
return totmsgs;
}
void bwave_create_packet() {
char buffer[1024];
char archive[1024];
INF_HEADER hdr;
struct ptr_vector areas;
INF_AREA_INFO *area = NULL;
2016-12-06 17:06:28 +10:00
int i;
int j;
int area_count;
tWORD flags;
int lasttot;
int last_ptr = 0;
2016-12-11 22:14:36 +10:00
int stout;
int stin;
int sterr;
char *weekday[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
struct stat s;
2016-12-06 17:06:28 +10:00
struct termios oldit;
struct termios oldot;
struct tm time_tm;
time_t thetime;
2016-12-06 17:06:28 +10:00
FILE *mix_file;
FILE *fti_file;
FILE *dat_file;
FILE *inf_file;
2017-09-21 10:21:51 +10:00
int tot_areas = 0;
2016-12-06 17:06:28 +10:00
int totmsgs = 0;
2018-02-09 19:35:14 +10:00
int ret;
char **args, *arg;
2018-06-20 19:31:35 +10:00
char *cmd;
pid_t pid;
2018-02-09 19:35:14 +10:00
init_ptr_vector(&areas);
for (size_t i = 0; i < ptr_vector_len(&conf.mail_conferences); i++) {
struct mail_conference *mc = ptr_vector_get(&conf.mail_conferences, i);
for (size_t j = 0; j < ptr_vector_len(&mc->mail_areas); j++) {
2017-09-21 10:21:51 +10:00
if (msgbase_is_subscribed(i, j)) {
tot_areas++;
}
}
}
2017-09-21 10:21:51 +10:00
if (tot_areas == 0) {
s_printf(get_string(224));
s_printf(get_string(6));
s_getchar();
return;
}
2016-12-06 17:06:28 +10:00
area_count = 0;
2016-12-06 17:06:28 +10:00
memset(&hdr, 0, sizeof(INF_HEADER));
hdr.ver = PACKET_LEVEL;
strlcpy(hdr.loginname, gUser->loginname, sizeof hdr.loginname);
//strlcpy(hdr.aliasname, gUser->loginname, sizeof hdr.aliasname);
snprintf(hdr.aliasname, sizeof hdr.aliasname, "%s %s", gUser->firstname, gUser->lastname);
2016-12-06 17:06:28 +10:00
hdr.zone = converts(conf.main_aka->zone);
hdr.node = converts(conf.main_aka->node);
hdr.net = converts(conf.main_aka->net);
hdr.point = converts(conf.main_aka->point);
strlcpy(hdr.sysop, conf.sysop_name, sizeof hdr.sysop);
strlcpy(hdr.systemname, conf.bbs_name, sizeof hdr.systemname);
2016-12-06 17:06:28 +10:00
hdr.inf_header_len = converts(sizeof(INF_HEADER));
hdr.inf_areainfo_len = converts(sizeof(INF_AREA_INFO));
hdr.mix_structlen = converts(sizeof(MIX_REC));
hdr.fti_structlen = converts(sizeof(FTI_REC));
hdr.uses_upl_file = 1;
hdr.from_to_len = 35;
hdr.subject_len = 71;
memcpy(hdr.packet_id, conf.bwave_name, strlen(conf.bwave_name));
snprintf(buffer, sizeof buffer, "%s/node%d", conf.bbs_path, mynode);
2016-12-07 09:24:15 +10:00
if (stat(buffer, &s) != 0) {
mkdir(buffer, 0755);
}
snprintf(buffer, sizeof buffer, "%s/node%d/bwave/", conf.bbs_path, mynode);
if (stat(buffer, &s) == 0) {
recursive_delete(buffer);
}
mkdir(buffer, 0755);
snprintf(buffer, sizeof buffer, "%s/node%d/bwave/%s.FTI", conf.bbs_path, mynode, conf.bwave_name);
fti_file = fopen(buffer, "wb");
snprintf(buffer, sizeof buffer, "%s/node%d/bwave/%s.MIX", conf.bbs_path, mynode, conf.bwave_name);
mix_file = fopen(buffer, "wb");
snprintf(buffer, sizeof buffer, "%s/node%d/bwave/%s.DAT", conf.bbs_path, mynode, conf.bwave_name);
dat_file = fopen(buffer, "wb");
2016-12-06 17:06:28 +10:00
s_printf("\r\n");
totmsgs = bwave_scan_email(area_count + 1, totmsgs, fti_file, mix_file, dat_file, &last_ptr);
s_printf(get_string(195), "Private Email", "Private Email", totmsgs);
2018-01-08 08:54:03 +10:00
flags = 0;
area = (INF_AREA_INFO *)malloz(sizeof(INF_AREA_INFO));
2018-01-08 08:54:03 +10:00
snprintf(area->areanum, 6, "%d", area_count + 1);
memcpy(area->echotag, "PRIVATE_EMAIL", 13);
strlcpy(area->title, "Private Email", 49);
2018-01-08 08:54:03 +10:00
flags |= INF_POST;
flags |= INF_NO_PUBLIC;
flags |= INF_SCANNING;
area->area_flags = converts(flags);
area->network_type = INF_NET_FIDONET;
ptr_vector_append(&areas, area);
2018-01-08 08:54:03 +10:00
area_count++;
2016-12-06 17:06:28 +10:00
2018-01-08 08:54:03 +10:00
if (totmsgs < conf.bwave_max_msgs) {
for (size_t i = 0; i < ptr_vector_len(&conf.mail_conferences); i++) {
struct mail_conference *mc = ptr_vector_get(&conf.mail_conferences, i);
for (size_t j = 0; j < ptr_vector_len(&mc->mail_areas); j++) {
struct mail_area *ma = get_area(i, j);
if (ma->read_sec_level <= gUser->sec_level && ma->qwkname != NULL && msgbase_is_subscribed(i, j)) {
2018-01-08 08:54:03 +10:00
lasttot = totmsgs;
totmsgs = bwave_scan_area(i, j, area_count + 1, totmsgs, fti_file, mix_file, dat_file, &last_ptr);
s_printf(get_string(195), mc->name, ma->name, totmsgs - lasttot);
2018-01-08 08:54:03 +10:00
//if (lasttot == totmsgs) {
// continue;
//}
area = (INF_AREA_INFO *)malloz(sizeof(INF_AREA_INFO));
snprintf(area->areanum, sizeof area->areanum, "%d", area_count + 1);
strlcpy(area->echotag, ma->qwkname, sizeof area->echotag);
strlcpy(area->title, ma->name, sizeof area->title);
flags = 0;
if (ma->write_sec_level <= gUser->sec_level) {
2018-01-08 08:54:03 +10:00
flags |= INF_POST;
}
if (ma->type == TYPE_NETMAIL_AREA) {
2018-01-08 08:54:03 +10:00
flags |= INF_NO_PUBLIC;
flags |= INF_NETMAIL;
flags |= INF_ECHO;
}
if (ma->type == TYPE_ECHOMAIL_AREA || ma->type == TYPE_NEWSGROUP_AREA) {
2018-01-08 08:54:03 +10:00
flags |= INF_NO_PRIVATE;
flags |= INF_ECHO;
}
if (ma->type == TYPE_LOCAL_AREA) {
2018-01-08 08:54:03 +10:00
flags |= INF_NO_PRIVATE;
}
2018-01-08 08:54:03 +10:00
flags |= INF_SCANNING;
area->area_flags = converts(flags);
area->network_type = INF_NET_FIDONET;
2018-01-08 08:54:03 +10:00
ptr_vector_append(&areas, area);
2018-01-08 08:54:03 +10:00
area_count++;
if (totmsgs == conf.bwave_max_msgs) {
break;
}
2016-12-06 17:06:28 +10:00
}
}
2018-01-08 08:54:03 +10:00
if (totmsgs == conf.bwave_max_msgs) {
break;
}
2016-12-06 17:06:28 +10:00
}
}
2018-01-08 08:54:03 +10:00
2016-12-06 17:06:28 +10:00
fclose(dat_file);
fclose(mix_file);
fclose(fti_file);
snprintf(buffer, 1024, "%s/node%d/bwave/%s.INF", conf.bbs_path, mynode, conf.bwave_name);
inf_file = fopen(buffer, "wb");
2016-12-06 17:06:28 +10:00
fwrite(&hdr, sizeof(INF_HEADER), 1, inf_file);
for (i = 0; i < area_count; i++) {
fwrite(ptr_vector_get(&areas, i), sizeof(INF_AREA_INFO), 1, inf_file);
2016-12-06 17:06:28 +10:00
}
2016-12-06 17:06:28 +10:00
fclose(inf_file);
More use of ptr_vector; avoid unnecessary copies. Recast more code in terms of the ptr_vector abstraction. The mail_menu.c code also made a lot of unnecessary copies of strings. For example, there was this code sequence: for (i = z; i < lines - 1; i++) { free(content[i]); content[i] = strdup(content[i + 1]); } free(content[i]); lines--; content = (char **)realloc(content, sizeof(char *) * lines); Here, `content` represents an array of lines of text. This code is removing an element from somewhere in that array (possibly in the middle), and then shifting the remaining elements over one position. But observe the calls to `free` and `strdup` in the loop body: the content is already dynamically allocated. We free whatever was in the selected position, and then make *another copy* of the data in the next position to put into the now-available slot in the array: repeat for the remainder of the array's elements. Instead, we could change this code to just shift things down: free(content[z]); for (i = z; i < (lines - 1); ++i) content[i] = content[i + 1]; --lines; ncontent = realloc(content, sizeof(char *) * lines); assert(ncontent == NULL); content = ncontent; However, the ptr_vector abstraction provides us a function, `ptr_vector_del` that deletes an element from the array and returns the pointer, so we can rewrite this as simply: free(ptr_vector_del(&content, z)); No additional malloc()/free() required, which means less pressure on the memory allocator and less copying of data. Signed-off-by: Dan Cross <patchdev@fat-dragon.org>
2018-10-10 17:50:37 +00:00
ptr_vector_apply(&areas, free);
destroy_ptr_vector(&areas);
2016-12-06 17:06:28 +10:00
if (totmsgs > 0) {
// create archive
if (gUser->bwavestyle) {
thetime = time(NULL);
localtime_r(&thetime, &time_tm);
if (gUser->bwavepktno / 10 != time_tm.tm_wday) {
gUser->bwavepktno = time_tm.tm_wday * 10;
}
snprintf(archive, sizeof archive, "%s/node%d/%s.%s%d",
conf.bbs_path, mynode, conf.bwave_name, weekday[time_tm.tm_wday], gUser->bwavepktno % 10);
} else {
snprintf(archive, sizeof archive, "%s/node%d/%s.%03d", conf.bbs_path, mynode, conf.bwave_name, gUser->bwavepktno);
}
struct archiver *arc = ptr_vector_get(&conf.archivers, gUser->defarchiver - 1);
assert(arc != NULL);
char *b = buffer;
size_t blen = sizeof buffer;
for (const char *p = arc->pack; *p != '\0' && blen >= 1; ++p) {
if (*p != '*') {
*b++ = *p;
--blen;
continue;
}
p++;
size_t alen = 0;
if (*p == 'a') {
strlcpy(b, archive, blen);
alen = strlen(archive);
} else if (*p == 'f') {
snprintf(b, blen, "%s/node%d/bwave/%s.INF %s/node%d/bwave/%s.MIX %s/node%d/bwave/%s.FTI %s/node%d/bwave/%s.DAT",
conf.bbs_path, mynode, conf.bwave_name, conf.bbs_path, mynode, conf.bwave_name, conf.bbs_path,
mynode, conf.bwave_name, conf.bbs_path, mynode, conf.bwave_name);
alen = strlen(b);
} else if (*p == '*') {
*b++ = '*';
alen = 1;
2016-12-06 17:06:28 +10:00
}
b += alen;
blen -= alen;
2016-12-06 17:06:28 +10:00
}
*b = '\0';
2016-12-11 22:14:36 +10:00
if (sshBBS) {
stout = dup(STDOUT_FILENO);
stin = dup(STDIN_FILENO);
sterr = dup(STDERR_FILENO);
2016-12-11 22:14:36 +10:00
dup2(bbs_stdout, STDOUT_FILENO);
dup2(bbs_stderr, STDERR_FILENO);
dup2(bbs_stdin, STDIN_FILENO);
}
args = split_on_space(buffer, NULL);
cmd = args[0];
2018-06-20 19:31:35 +10:00
pid = fork();
if (pid == 0) {
execvp(cmd, args);
exit(0);
} else if (pid > 0) {
waitpid(pid, &ret, 0);
} else {
ret = -1;
}
free(args);
2016-12-11 22:14:36 +10:00
if (sshBBS) {
2016-12-11 22:14:36 +10:00
dup2(stout, STDOUT_FILENO);
dup2(sterr, STDERR_FILENO);
2016-12-11 22:14:36 +10:00
dup2(stin, STDIN_FILENO);
2016-12-11 22:14:36 +10:00
close(stin);
close(stout);
close(sterr);
}
2016-12-06 17:06:28 +10:00
2018-02-09 19:35:14 +10:00
if (ret != -1 && ret >> 8 != 127) {
do_download(gUser, archive);
} else {
s_printf(get_string(274));
}
snprintf(buffer, 1024, "%s/node%d/bwave", conf.bbs_path, mynode);
recursive_delete(buffer);
2016-12-06 17:06:28 +10:00
unlink(archive);
gUser->bwavepktno++;
if (gUser->bwavepktno > 999) {
gUser->bwavepktno = 0;
}
2016-12-06 17:06:28 +10:00
save_user(gUser);
}
2016-12-06 17:06:28 +10:00
s_printf(get_string(6));
s_getc();
}
int bwave_add_message(int confr, int area, unsigned int dwritten, char *to, char *subject, struct fido_addr *destaddr, char *msg) {
s_JamBase *jb;
s_JamMsgHeader jmh;
s_JamSubPacket *jsp;
2016-12-06 17:06:28 +10:00
s_JamSubfield jsf;
int z;
char buffer[256];
2018-05-22 21:02:22 +10:00
uuid_t magi_msgid;
struct mail_area *ma = get_area(confr, area);
jb = open_jam_base(ma->path);
2016-12-06 17:06:28 +10:00
if (!jb) {
dolog("Error opening JAM base.. %s", ma->path);
2016-12-06 17:06:28 +10:00
return 1;
}
JAM_ClearMsgHeader(&jmh);
2016-12-06 17:06:28 +10:00
jmh.DateWritten = dwritten;
jmh.Attribute |= JAM_MSG_LOCAL;
struct mail_conference *mc = get_conf(confr);
if (mc->realnames == 0) {
strlcpy(buffer, gUser->loginname, sizeof buffer);
2016-12-06 17:06:28 +10:00
} else {
snprintf(buffer, sizeof buffer, "%s %s", gUser->firstname, gUser->lastname);
2016-12-06 17:06:28 +10:00
}
jsp = JAM_NewSubPacket();
jsf.LoID = JAMSFLD_SENDERNAME;
jsf.HiID = 0;
2016-12-06 17:06:28 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
if (ma->type == TYPE_NEWSGROUP_AREA) {
strlcpy(buffer, "ALL", sizeof buffer);
jsf.LoID = JAMSFLD_RECVRNAME;
jsf.HiID = 0;
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
} else {
jsf.LoID = JAMSFLD_RECVRNAME;
jsf.HiID = 0;
jsf.DatLen = strlen(to);
jsf.Buffer = (char *)to;
JAM_PutSubfield(jsp, &jsf);
}
2016-12-06 17:06:28 +10:00
jsf.LoID = JAMSFLD_SUBJECT;
jsf.HiID = 0;
2016-12-06 17:06:28 +10:00
jsf.DatLen = strlen(subject);
jsf.Buffer = (char *)subject;
JAM_PutSubfield(jsp, &jsf);
if (ma->type == TYPE_ECHOMAIL_AREA || ma->type == TYPE_NEWSGROUP_AREA) {
jmh.Attribute |= JAM_MSG_TYPEECHO;
struct mail_conference *mc = get_conf(confr);
if (mc->nettype == NETWORK_FIDO) {
if (mc->fidoaddr->point) {
snprintf(buffer, sizeof buffer, "%d:%d/%d.%d",
mc->fidoaddr->zone,
mc->fidoaddr->net,
mc->fidoaddr->node,
mc->fidoaddr->point);
2018-05-22 21:02:22 +10:00
} else {
snprintf(buffer, sizeof buffer, "%d:%d/%d",
mc->fidoaddr->zone,
mc->fidoaddr->net,
mc->fidoaddr->node);
2018-05-22 21:02:22 +10:00
}
jsf.LoID = JAMSFLD_OADDRESS;
jsf.HiID = 0;
2018-05-22 21:02:22 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
2016-12-06 17:06:28 +10:00
snprintf(buffer, sizeof buffer, "%d:%d/%d.%d %08lx",
mc->fidoaddr->zone,
mc->fidoaddr->net,
mc->fidoaddr->node,
mc->fidoaddr->point,
generate_msgid());
2016-12-06 17:06:28 +10:00
jsf.LoID = JAMSFLD_MSGID;
jsf.HiID = 0;
2018-05-22 21:02:22 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
jmh.MsgIdCRC = JAM_Crc32(buffer, strlen(buffer));
} else if (mc->nettype == NETWORK_MAGI) {
snprintf(buffer, sizeof buffer, "%d", mc->maginode);
jsf.LoID = JAMSFLD_OADDRESS;
jsf.HiID = 0;
2018-05-22 21:02:22 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
uuid_generate(magi_msgid);
uuid_unparse_lower(magi_msgid, buffer);
jsf.LoID = JAMSFLD_MSGID;
jsf.HiID = 0;
2018-05-22 21:02:22 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
jmh.MsgIdCRC = JAM_Crc32(buffer, strlen(buffer));
} else if (mc->nettype == NETWORK_QWK) {
jsf.LoID = JAMSFLD_OADDRESS;
jsf.HiID = 0;
2018-06-24 10:28:18 +10:00
jsf.DatLen = strlen(conf.bwave_name);
jsf.Buffer = (char *)conf.bwave_name;
JAM_PutSubfield(jsp, &jsf);
2018-05-22 21:02:22 +10:00
}
} else if (ma->type == TYPE_NETMAIL_AREA && mc->nettype == NETWORK_FIDO) {
jmh.Attribute |= JAM_MSG_TYPENET;
jmh.Attribute |= JAM_MSG_PRIVATE;
if (mc->fidoaddr->point) {
snprintf(buffer, sizeof buffer, "%d:%d/%d.%d",
mc->fidoaddr->zone,
mc->fidoaddr->net,
mc->fidoaddr->node,
mc->fidoaddr->point);
2016-12-06 17:06:28 +10:00
} else {
snprintf(buffer, sizeof buffer, "%d:%d/%d",
mc->fidoaddr->zone,
mc->fidoaddr->net,
mc->fidoaddr->node);
2016-12-06 17:06:28 +10:00
}
jsf.LoID = JAMSFLD_OADDRESS;
jsf.HiID = 0;
2016-12-06 17:06:28 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
if (destaddr != NULL) {
if (destaddr->point) {
snprintf(buffer, sizeof buffer, "%d:%d/%d.%d",
destaddr->zone,
destaddr->net,
destaddr->node,
destaddr->point);
2016-12-06 17:06:28 +10:00
} else {
snprintf(buffer, sizeof buffer, "%d:%d/%d",
destaddr->zone,
destaddr->net,
destaddr->node);
2016-12-06 17:06:28 +10:00
}
jsf.LoID = JAMSFLD_DADDRESS;
jsf.HiID = 0;
2016-12-06 17:06:28 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
}
snprintf(buffer, sizeof buffer, "%d:%d/%d.%d %08lx",
mc->fidoaddr->zone,
mc->fidoaddr->net,
mc->fidoaddr->node,
mc->fidoaddr->point,
generate_msgid());
2016-12-06 17:06:28 +10:00
jsf.LoID = JAMSFLD_MSGID;
jsf.HiID = 0;
2016-12-06 17:06:28 +10:00
jsf.DatLen = strlen(buffer);
jsf.Buffer = (char *)buffer;
JAM_PutSubfield(jsp, &jsf);
jmh.MsgIdCRC = JAM_Crc32(buffer, strlen(buffer));
}
while (1) {
z = JAM_LockMB(jb, 100);
if (z == 0) {
break;
} else if (z == JAM_LOCK_FAILED) {
sleep(1);
} else {
dolog("Failed to lock msg base!");
2018-02-10 16:01:30 +10:00
JAM_CloseMB(jb);
free(jb);
2016-12-06 17:06:28 +10:00
return 1;
}
}
if (JAM_AddMessage(jb, &jmh, jsp, (char *)msg, strlen(msg))) {
dolog("Failed to add message");
JAM_UnlockMB(jb);
2016-12-06 17:06:28 +10:00
JAM_DelSubPacket(jsp);
JAM_CloseMB(jb);
2018-02-10 16:01:30 +10:00
free(jb);
2016-12-06 17:06:28 +10:00
return -1;
} else {
JAM_UnlockMB(jb);
JAM_DelSubPacket(jsp);
JAM_CloseMB(jb);
2018-02-10 16:01:30 +10:00
free(jb);
2016-12-06 17:06:28 +10:00
}
return 0;
}
void bwave_upload_reply() {
char buffer[1024];
char msgbuffer[1024];
char originlinebuffer[256];
int i;
UPL_HEADER upl_hdr;
UPL_REC upl_rec;
int j;
int confr;
int area;
tWORD msg_attr;
struct fido_addr addr;
stralloc sa = EMPTY_STRALLOC;
2016-12-06 17:06:28 +10:00
char *body;
char *tagline;
struct stat s;
2016-12-06 17:06:28 +10:00
int echomail = 0;
int netmail = 0;
FILE *upl_file;
FILE *msg_file;
int sem_fd;
int msg_count;
2016-12-11 22:14:36 +10:00
int stout;
int stin;
int sterr;
2018-01-08 08:54:03 +10:00
sqlite3 *db;
sqlite3_stmt *res;
int rc;
2018-01-08 08:54:03 +10:00
char *csql = "CREATE TABLE IF NOT EXISTS email ("
"id INTEGER PRIMARY KEY,"
"sender TEXT COLLATE NOCASE,"
"recipient TEXT COLLATE NOCASE,"
"subject TEXT,"
"body TEXT,"
"date INTEGER,"
"seen INTEGER);";
2018-01-08 08:54:03 +10:00
char *isql = "INSERT INTO email (sender, recipient, subject, body, date, seen) VALUES(?, ?, ?, ?, ?, 0)";
char *err_msg = 0;
char **args, *arg;
2018-06-20 19:31:35 +10:00
char *cmd;
pid_t pid;
int ret;
msg_count = 0;
2016-12-07 09:24:15 +10:00
snprintf(buffer, 1024, "%s/node%d", conf.bbs_path, mynode);
if (stat(buffer, &s) != 0) {
mkdir(buffer, 0755);
}
snprintf(buffer, 1024, "%s/node%d/bwave/", conf.bbs_path, mynode);
if (stat(buffer, &s) == 0) {
recursive_delete(buffer);
}
mkdir(buffer, 0755);
if (!do_upload(gUser, buffer)) {
s_printf(get_string(211));
recursive_delete(buffer);
return;
}
struct archiver *arc = ptr_vector_get(&conf.archivers, gUser->defarchiver - 1);
assert(arc != NULL);
char *b = buffer;
size_t blen = sizeof buffer;
for (const char *p = arc->unpack; *p != '\0' && blen > 1; ++p) {
if (*p != '*') {
*b++ = *p;
--blen;
continue;
}
p++;
size_t alen = 0;
if (*p == 'a') {
strlcpy(b, upload_filename, blen);
alen = strlen(upload_filename);
} else if (*p == 'd') {
snprintf(b, blen, "%s/node%d/bwave/", conf.bbs_path, mynode);
alen = strlen(b);
} else if (*p == '*') {
*b++ = '*';
alen = 1;
2016-12-06 17:06:28 +10:00
}
b += alen;
blen -= alen;
2016-12-06 17:06:28 +10:00
}
*b = '\0';
2016-12-11 22:14:36 +10:00
if (sshBBS) {
stout = dup(STDOUT_FILENO);
stin = dup(STDIN_FILENO);
sterr = dup(STDERR_FILENO);
2016-12-11 22:14:36 +10:00
dup2(bbs_stdout, STDOUT_FILENO);
dup2(bbs_stderr, STDERR_FILENO);
dup2(bbs_stdin, STDIN_FILENO);
}
args = split_on_space(buffer, NULL);
cmd = args[0];
2018-06-20 19:31:35 +10:00
pid = fork();
if (pid == 0) {
execvp(cmd, args);
exit(0);
} else if (pid > 0) {
waitpid(pid, &ret, 0);
} else {
ret = -1;
}
free(args);
2016-12-11 22:14:36 +10:00
if (sshBBS) {
2016-12-11 22:14:36 +10:00
dup2(stout, STDOUT_FILENO);
dup2(sterr, STDERR_FILENO);
2016-12-11 22:14:36 +10:00
dup2(stin, STDIN_FILENO);
2016-12-11 22:14:36 +10:00
close(stin);
close(stout);
close(sterr);
}
2016-12-06 17:06:28 +10:00
unlink(upload_filename);
snprintf(buffer, sizeof buffer, "%s/node%d/bwave/%s.UPL", conf.bbs_path, mynode, conf.bwave_name);
2016-12-06 17:06:28 +10:00
upl_file = fopen(buffer, "r");
2016-12-06 17:06:28 +10:00
if (!upl_file) {
snprintf(buffer, sizeof buffer, "%s/node%d/bwave/%s.upl", conf.bbs_path, mynode, conf.bwave_name);
2016-12-06 17:06:28 +10:00
upl_file = fopen(buffer, "r");
if (!upl_file) {
s_printf(get_string(196));
return;
}
}
2016-12-06 17:06:28 +10:00
if (!fread(&upl_hdr, sizeof(UPL_HEADER), 1, upl_file)) {
s_printf(get_string(196));
fclose(upl_file);
return;
2016-12-06 17:06:28 +10:00
}
2016-12-06 17:06:28 +10:00
while (fread(&upl_rec, sizeof(UPL_REC), 1, upl_file)) {
2018-01-08 08:54:03 +10:00
if (strcmp("PRIVATE_EMAIL", upl_rec.echotag) == 0) {
if (msg_attr & UPL_INACTIVE) {
continue;
}
2018-01-08 08:54:03 +10:00
if (strcasecmp(upl_rec.from, gUser->loginname) != 0) {
continue;
}
snprintf(msgbuffer, 1024, "%s/node%d/bwave/%s", conf.bbs_path, mynode, upl_rec.filename);
body = file2str(msgbuffer);
if (body == NULL) {
2018-01-08 08:54:03 +10:00
continue;
2016-12-06 17:06:28 +10:00
}
char *b = body;
for (char *p = body; *p != '\0'; ++p) {
if (*p != '\n')
*b++ = *p;
2016-12-06 17:06:28 +10:00
}
*b = '\0';
2018-01-08 08:54:03 +10:00
snprintf(buffer, sizeof buffer, "%s/email.sq3", conf.bbs_path);
2018-01-08 08:54:03 +10:00
rc = sqlite3_open(buffer, &db);
2018-01-08 08:54:03 +10:00
if (rc != SQLITE_OK) {
dolog("Cannot open database: %s", sqlite3_errmsg(db));
sqlite3_close(db);
free(body);
continue;
}
sqlite3_busy_timeout(db, 5000);
rc = sqlite3_exec(db, csql, 0, 0, &err_msg);
if (rc != SQLITE_OK) {
2018-01-08 08:54:03 +10:00
dolog("SQL error: %s", err_msg);
sqlite3_free(err_msg);
sqlite3_close(db);
free(body);
continue;
}
rc = sqlite3_prepare_v2(db, isql, -1, &res, 0);
if (rc == SQLITE_OK) {
sqlite3_bind_text(res, 1, gUser->loginname, -1, 0);
sqlite3_bind_text(res, 2, upl_rec.to, -1, 0);
sqlite3_bind_text(res, 3, upl_rec.subj, -1, 0);
sqlite3_bind_text(res, 4, body, -1, 0);
sqlite3_bind_int(res, 5, convertl(upl_rec.unix_date));
} else {
dolog("Failed to execute statement: %s", sqlite3_errmsg(db));
sqlite3_finalize(res);
sqlite3_close(db);
free(body);
continue;
}
sqlite3_step(res);
sqlite3_finalize(res);
sqlite3_close(db);
free(body);
msg_count++;
2018-01-08 08:54:03 +10:00
} else {
// find area
confr = -1;
area = -1;
for (i = 0; i < ptr_vector_len(&conf.mail_conferences); i++) {
struct mail_conference *mc = ptr_vector_get(&conf.mail_conferences, i);
for (j = 0; j < ptr_vector_len(&mc->mail_areas); j++) {
struct mail_area *ma = ptr_vector_get(&mc->mail_areas, j);
if (strcmp(ma->qwkname, upl_rec.echotag) == 0) {
2018-01-08 08:54:03 +10:00
confr = i;
area = j;
break;
}
2016-12-06 17:06:28 +10:00
}
2018-01-08 08:54:03 +10:00
if (confr != -1) {
break;
2016-12-06 17:06:28 +10:00
}
2018-01-08 08:54:03 +10:00
}
2018-01-08 08:54:03 +10:00
if (confr != -1 && area != -1) {
// import message
struct mail_area *ma = get_area(confr, area);
if (ma->write_sec_level <= gUser->sec_level) {
2018-01-08 08:54:03 +10:00
msg_attr = converts(upl_rec.msg_attr);
2018-01-08 08:54:03 +10:00
if (msg_attr & UPL_INACTIVE) {
2016-12-06 17:06:28 +10:00
continue;
}
2018-01-08 08:54:03 +10:00
if (strcasecmp(upl_rec.from, gUser->loginname) != 0) {
2016-12-06 17:06:28 +10:00
continue;
}
2018-01-08 08:54:03 +10:00
addr.zone = 0;
addr.net = 0;
addr.node = 0;
addr.zone = 0;
if (ma->type == TYPE_NETMAIL_AREA) {
2018-01-08 08:54:03 +10:00
if (!(msg_attr & UPL_NETMAIL)) {
continue;
}
addr.zone = converts(upl_rec.destzone);
addr.net = converts(upl_rec.destnet);
addr.node = converts(upl_rec.destnode);
addr.zone = converts(upl_rec.destpoint);
netmail = 1;
} else if (ma->type == TYPE_ECHOMAIL_AREA || ma->type == TYPE_NEWSGROUP_AREA) {
2018-01-08 08:54:03 +10:00
if (msg_attr & UPL_PRIVATE) {
continue;
}
echomail = 1;
} else { // Local area
if (msg_attr & UPL_PRIVATE) {
continue;
}
2018-01-08 08:54:03 +10:00
}
snprintf(msgbuffer, sizeof buffer, "%s/node%d/bwave/%s", conf.bbs_path, mynode, upl_rec.filename);
tagline = conf.default_tagline;
struct mail_conference *mc = get_conf(confr);
if (mc->tagline != NULL) {
tagline = mc->tagline;
2018-01-08 08:54:03 +10:00
}
if (mc->nettype == NETWORK_FIDO) {
if (mc->fidoaddr->point == 0) {
snprintf(originlinebuffer, sizeof originlinebuffer, "\r--- %s\r * Origin: %s (%d:%d/%d)\r",
upl_hdr.reader_tear, tagline,
mc->fidoaddr->zone, mc->fidoaddr->net, mc->fidoaddr->node);
2018-01-08 08:54:03 +10:00
} else {
snprintf(originlinebuffer, sizeof originlinebuffer, "\r--- %s\r * Origin: %s (%d:%d/%d.%d)\r",
upl_hdr.reader_tear, tagline,
mc->fidoaddr->zone,
mc->fidoaddr->net,
mc->fidoaddr->node,
mc->fidoaddr->point);
2018-01-08 08:54:03 +10:00
}
} else if (mc->nettype == NETWORK_MAGI) {
snprintf(originlinebuffer, sizeof originlinebuffer, "\r--- %s\r * Origin: %s (@%d)\r",
upl_hdr.reader_tear, tagline, mc->maginode);
} else if (mc->nettype == NETWORK_QWK) {
snprintf(originlinebuffer, sizeof originlinebuffer, "\r--- $s\r * Origin: %s (%s)\r",
upl_hdr.reader_tear, tagline, conf.bwave_name);
2018-01-08 08:54:03 +10:00
} else {
snprintf(originlinebuffer, sizeof originlinebuffer, "\r");
2016-12-06 17:06:28 +10:00
}
sa = file2stralloc(msgbuffer);
if (sa.s == NULL) {
2018-01-08 08:54:03 +10:00
continue;
2016-12-06 17:06:28 +10:00
}
stralloc_cats(&sa, originlinebuffer);
stralloc_0(&sa);
body = sa.s;
char *p, *s;
for (p = s = body; *p != '\0'; ++p) {
if (*p != '\n')
*s++ = *p;
2018-01-08 08:54:03 +10:00
}
*s = '\0';
2018-01-08 08:54:03 +10:00
if (bwave_add_message(confr, area, convertl(upl_rec.unix_date), upl_rec.to, upl_rec.subj, &addr, body) != 0) {
// failed to add message
s_printf(get_string(197));
} else {
msg_count++;
}
2018-01-08 08:54:03 +10:00
free(body);
2016-12-06 17:06:28 +10:00
}
}
}
}
2018-01-08 08:54:03 +10:00
snprintf(buffer, sizeof buffer, "%s/node%d/bwave/", conf.bbs_path, mynode);
recursive_delete(buffer);
if (netmail == 1) {
if (conf.netmail_sem != NULL) {
sem_fd = open(conf.netmail_sem, O_RDWR | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
close(sem_fd);
}
}
if (echomail == 1) {
if (conf.echomail_sem != NULL) {
sem_fd = open(conf.echomail_sem, O_RDWR | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
close(sem_fd);
}
}
2016-12-06 17:06:28 +10:00
s_printf("\r\n");
if (msg_count > 0) {
s_printf(get_string(204), msg_count);
}
2016-12-06 17:06:28 +10:00
s_printf(get_string(6));
s_getc();
}