-
Rob Swindell authored
Before now, the archive formats/types (e.g. for creating QWK/REP packets or temp file download archives) supported by libarchive have been *hard-coded* in Synchronet to "zip, 7z, tgz", but if you really want to support the creation of more archive formats using the internal (libarchive) support in Synchronet, and your system supports it (e.g. confirmed using archive.js), you can add those types to this list or remove any that are problematic. This list does not impact the archive types that can be viewed or extracted using libarchive.
Rob Swindell authoredBefore now, the archive formats/types (e.g. for creating QWK/REP packets or temp file download archives) supported by libarchive have been *hard-coded* in Synchronet to "zip, 7z, tgz", but if you really want to support the creation of more archive formats using the internal (libarchive) support in Synchronet, and your system supports it (e.g. confirmed using archive.js), you can add those types to this list or remove any that are problematic. This list does not impact the archive types that can be viewed or extracted using libarchive.
pack_rep.cpp 12.50 KiB
/* Synchronet QWK reply (REP) packet creation routine */
/****************************************************************************
* @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"
#include "filedat.h"
/****************************************************************************/
/* Creates an REP packet for upload to QWK hub 'hubnum'. */
/* Returns 1 if successful, 0 if not. */
/****************************************************************************/
bool sbbs_t::pack_rep(uint hubnum)
{
char str[MAX_PATH + 1];
char tmp[MAX_PATH + 1], tmp2[MAX_PATH + 1];
char hubid_upper[LEN_QWKID + 1];
char hubid_lower[LEN_QWKID + 1];
char error[256];
int mode;
const char* fmode;
int i, j, k;
long msgcnt, submsgs, packedmail, netfiles = 0, deleted;
uint32_t u;
uint32_t posts;
uint32_t mailmsgs;
ulong msgs;
uint32_t last;
post_t* post;
mail_t* mail;
FILE* rep;
FILE* hdrs = NULL;
FILE* voting = NULL;
DIR* dir;
DIRENT* dirent;
smbmsg_t msg;
msgcnt = 0L;
delfiles(cfg.temp_dir, ALLFILES);
SAFECOPY(hubid_upper, cfg.qhub[hubnum]->id);
strupr(hubid_upper);
SAFECOPY(hubid_lower, cfg.qhub[hubnum]->id);
strlwr(hubid_lower);
SAFEPRINTF2(str, "%s%s.REP", cfg.data_dir, hubid_upper);
if (fexistcase(str)) {
lprintf(LOG_INFO, "Updating %s", str);
long file_count = extract_files_from_archive(str
, /* outdir: */ cfg.temp_dir
, /* allowed_filename_chars: */ NULL /* any */
, /* with_path: */ false
, /* overwrite: */ true
, /* max_files: */ 0 /* unlimited */
, /* file_list: */ NULL /* all files */
, /* recurse: */ false
, error, sizeof(error));
if (file_count > 0) {
lprintf(LOG_DEBUG, "libarchive extracted %lu files from %s", file_count, str);
} else {
if (*error)
lprintf(LOG_NOTICE, "libarchive error (%s) extracting %s", error, str);
if (*cfg.qhub[hubnum]->unpack)
external(cmdstr(cfg.qhub[hubnum]->unpack, str, ALLFILES, NULL), EX_OFFLINE);
}
} else
lprintf(LOG_INFO, "Creating %s", str);
/*************************************************/
/* Create SYSID.MSG, write header and leave open */
/*************************************************/
SAFEPRINTF2(str, "%s%s.MSG", cfg.temp_dir, hubid_upper);
if (fexistcase(str))
fmode = "r+b";
else
fmode = "w+b";
if ((rep = fopen(str, fmode)) == NULL) {
errormsg(WHERE, ERR_CREATE, str, 0, fmode);
return false;
}
fseek(rep, 0, SEEK_END);
if (ftell(rep) < 1) { /* New REP packet */
fprintf(rep, "%-*s"
, QWK_BLOCK_LEN, hubid_upper); /* So write header */
}
if (!(cfg.qhub[hubnum]->misc & QHUB_NOHEADERS)) {
SAFEPRINTF(str, "%sHEADERS.DAT", cfg.temp_dir);
fexistcase(str);
if ((hdrs = fopen(str, "a")) == NULL)
errormsg(WHERE, ERR_CREATE, str, 0);
}
if (!(cfg.qhub[hubnum]->misc & QHUB_NOVOTING)) {
SAFEPRINTF(str, "%sVOTING.DAT", cfg.temp_dir);
fexistcase(str);
if ((voting = fopen(str, "a")) == NULL)
errormsg(WHERE, ERR_CREATE, str, 0);
}
/*********************/
/* Pack new messages */
/*********************/
SAFEPRINTF(smb.file, "%smail", cfg.data_dir);
smb.retry_time = cfg.smb_retry_time;
smb.subnum = INVALID_SUB;
if ((i = smb_open(&smb)) != 0) {
fclose(rep);
if (hdrs != NULL)
fclose(hdrs);
if (voting != NULL)
fclose(voting);
errormsg(WHERE, ERR_OPEN, smb.file, i, smb.last_error);
return false;
}
/***********************/
/* Pack E-mail, if any */
/***********************/
qwkmail_last = 0;
mail = loadmail(&smb, &mailmsgs, 0, MAIL_YOUR, 0);
packedmail = 0;
if (mailmsgs) {
lprintf(LOG_INFO, "Packing NetMail for %s", cfg.qhub[hubnum]->id);
for (u = 0; u < mailmsgs; u++) {
// bprintf("\b\b\b\b\b%-5lu",u+1);
memset(&msg, 0, sizeof(msg));
msg.idx = mail[u];
if (msg.idx.number > qwkmail_last)
qwkmail_last = msg.idx.number;
if (loadmsg(&msg, mail[u].number) < 1)
continue;
SAFEPRINTF(str, "%s/", cfg.qhub[hubnum]->id);
if (msg.to_net.type != NET_QWK
|| (strcmp((char *)msg.to_net.addr, cfg.qhub[hubnum]->id)
&& strncmp((char *)msg.to_net.addr, str, strlen(str)))) {
smb_unlockmsghdr(&smb, &msg);
smb_freemsgmem(&msg);
continue;
}
mode = QM_TO_QNET | QM_REP;
mode |= (cfg.qhub[hubnum]->misc & (QHUB_EXT | QHUB_CTRL_A | QHUB_UTF8));
/* For an unclear reason, kludge lines (including @VIA and @TZ) were not included in NetMail previously */
if (!(cfg.qhub[hubnum]->misc & QHUB_NOHEADERS))
mode |= (QM_VIA | QM_TZ | QM_MSGID | QM_REPLYTO);
if (msgtoqwk(&msg, rep, mode, &smb, /* confnum: */ 0, hdrs) > 0)
packedmail++;
smb_unlockmsghdr(&smb, &msg);
smb_freemsgmem(&msg);
YIELD(); /* yield */
}
lprintf(LOG_INFO, "Packed %ld NetMail messages", packedmail);
}
smb_close(&smb); /* Close the e-mail */
if (mailmsgs)
free(mail);
for (i = 0; i < cfg.qhub[hubnum]->subs; i++) {
j = cfg.qhub[hubnum]->sub[i]->subnum; /* j now equals the real sub num */
msgs = getlastmsg(j, &last, 0);
lncntr = 0; /* defeat pause */
if (!msgs || last <= subscan[j].ptr) {
if (subscan[j].ptr > last) {
subscan[j].ptr = last;
subscan[j].last = last;
}
lprintf(LOG_INFO, remove_ctrl_a(text[NScanStatusFmt], tmp)
, cfg.grp[cfg.sub[j]->grp]->sname
, cfg.sub[j]->lname, 0L, msgs);
continue;
}
SAFEPRINTF2(smb.file, "%s%s"
, cfg.sub[j]->data_dir, cfg.sub[j]->code);
smb.retry_time = cfg.smb_retry_time;
smb.subnum = j;
if ((k = smb_open(&smb)) != 0) {
errormsg(WHERE, ERR_OPEN, smb.file, k, smb.last_error);
continue;
}
post = loadposts(&posts, j, subscan[j].ptr, LP_BYSELF | LP_OTHERS | LP_PRIVATE | LP_REP | LP_VOTES | LP_POLLS, NULL);
lprintf(LOG_INFO, remove_ctrl_a(text[NScanStatusFmt], tmp)
, cfg.grp[cfg.sub[j]->grp]->sname
, cfg.sub[j]->lname, posts, msgs);
if (!posts) { /* no new messages */
smb_close(&smb);
continue;
}
subscan[j].ptr = last; /* set pointer */
lprintf(LOG_INFO, "%s", remove_ctrl_a(text[QWKPackingSubboard], tmp)); /* ptr to last msg */
submsgs = 0;
for (u = 0; u < posts; u++) {
// bprintf("\b\b\b\b\b%-5lu",u+1);
memset(&msg, 0, sizeof(msg));
msg.idx = post[u].idx;
if (loadmsg(&msg, post[u].idx.number) < 1)
continue;
if (msg.from_net.type && msg.from_net.type != NET_QWK &&
!(cfg.sub[j]->misc & SUB_GATE)) {
smb_freemsgmem(&msg);
smb_unlockmsghdr(&smb, &msg);
continue;
}
if (!strnicmp(msg.subj, "NE:", 3) || (msg.from_net.type == NET_QWK &&
route_circ((char *)msg.from_net.addr, cfg.qhub[hubnum]->id))) {
smb_freemsgmem(&msg);
smb_unlockmsghdr(&smb, &msg);
continue;
}
mode = cfg.qhub[hubnum]->mode[i] | QM_TO_QNET | QM_REP;
mode |= (cfg.qhub[hubnum]->misc & (QHUB_EXT | QHUB_CTRL_A | QHUB_UTF8));
if (!(cfg.qhub[hubnum]->misc & QHUB_NOHEADERS))
mode |= (QM_VIA | QM_TZ | QM_MSGID | QM_REPLYTO);
if (msg.from_net.type != NET_QWK)
mode |= QM_TAGLINE;
if (msgtoqwk(&msg, rep, mode, &smb, cfg.qhub[hubnum]->conf[i], hdrs, voting) > 0) {
msgcnt++;
submsgs++;
}
smb_freemsgmem(&msg);
smb_unlockmsghdr(&smb, &msg);
if (!(u % 50))
YIELD(); /* yield */
}
lprintf(LOG_INFO, remove_ctrl_a(text[QWKPackedSubboard], tmp), submsgs, msgcnt);
free(post);
smb_close(&smb);
YIELD(); /* yield */
}
BOOL voting_data = FALSE;
if (hdrs != NULL)
fclose(hdrs);
if (voting != NULL) {
voting_data = ftell(voting);
fclose(voting);
}
fclose(rep); /* close HUB_ID.MSG */
CRLF;
/* Look for extra files to send out */
SAFEPRINTF2(str, "%sqnet/%s.out", cfg.data_dir, hubid_lower);
dir = opendir(str);
while (dir != NULL && (dirent = readdir(dir)) != NULL) {
SAFEPRINTF3(str, "%sqnet/%s.out/%s", cfg.data_dir, hubid_lower, dirent->d_name);
if (isdir(str))
continue;
SAFEPRINTF2(tmp2, "%s%s", cfg.temp_dir, dirent->d_name);
lprintf(LOG_INFO, remove_ctrl_a(text[RetrievingFile], tmp), str);
if (!mv(str, tmp2, /* copy: */ TRUE))
netfiles++;
}
if (dir != NULL)
closedir(dir);
if (netfiles)
CRLF;
if (!msgcnt && !netfiles && !packedmail && !voting_data) {
lprintf(LOG_INFO, "%s", remove_ctrl_a(text[QWKNoNewMessages], tmp));
return true; // Changed from false Mar-11-2005 (needs to be true to save updated ptrs)
}
/*******************/
/* Compress Packet */
/*******************/
SAFEPRINTF2(str, "%s%s.REP", cfg.data_dir, hubid_upper);
SAFEPRINTF2(tmp2, "%s%s", cfg.temp_dir, ALLFILES);
if (strListFind(cfg.supported_archive_formats, cfg.qhub[hubnum]->fmt, /* case_sensitive */ FALSE) >= 0) {
str_list_t file_list = directory(tmp2);
long file_count = create_archive(str, cfg.qhub[hubnum]->fmt, /* with_path: */ false, file_list, error, sizeof(error));
strListFree(&file_list);
if (file_count < 0)
lprintf(LOG_ERR, "libarchive error %ld (%s) creating %s", file_count, error, str);
else
lprintf(LOG_INFO, "libarchive created %s from %ld files", str, file_count);
} else {
i = external(cmdstr(cfg.qhub[hubnum]->pack, str, tmp2, NULL)
, EX_OFFLINE | EX_WILDCARD);
if (i)
errormsg(WHERE, ERR_EXEC, cmdstr(cfg.qhub[hubnum]->pack, str, tmp2, NULL), i);
}
if (!fexistcase(str)) {
lprintf(LOG_WARNING, "%s", remove_ctrl_a(text[QWKCompressionFailed], tmp));
lprintf(LOG_ERR, "Couldn't compress REP packet");
return false;
}
SAFEPRINTF2(str, "%sqnet/%s.out/", cfg.data_dir, hubid_lower);
delfiles(str, ALLFILES);
if (packedmail) { /* Delete NetMail */
SAFEPRINTF(smb.file, "%smail", cfg.data_dir);
smb.retry_time = cfg.smb_retry_time;
smb.subnum = INVALID_SUB;
if ((i = smb_open(&smb)) != 0) {
errormsg(WHERE, ERR_OPEN, smb.file, i, smb.last_error);
return true;
}
mail = loadmail(&smb, &mailmsgs, 0, MAIL_YOUR, 0);
if ((i = smb_locksmbhdr(&smb)) != 0) { /* Lock the base, so nobody */
if (mailmsgs)
free(mail);
smb_close(&smb);
errormsg(WHERE, ERR_LOCK, smb.file, i, smb.last_error); /* messes with the index */
return true;
}
if ((i = smb_getstatus(&smb)) != 0) {
if (mailmsgs)
free(mail);
smb_close(&smb);
errormsg(WHERE, ERR_READ, smb.file, i, smb.last_error);
return true;
}
deleted = 0;
/* Mark as READ and DELETE */
for (u = 0; u < mailmsgs; u++) {
if (mail[u].number > qwkmail_last)
continue;
memset(&msg, 0, sizeof(msg));
/* !IMPORTANT: search by number (do not initialize msg.idx.offset) */
if (loadmsg(&msg, mail[u].number) < 1)
continue;
SAFEPRINTF(str, "%s/", cfg.qhub[hubnum]->id);
if (msg.to_net.type != NET_QWK
|| (strcmp((char *)msg.to_net.addr, cfg.qhub[hubnum]->id)
&& strncmp((char *)msg.to_net.addr, str, strlen(str)))) {
smb_unlockmsghdr(&smb, &msg);
smb_freemsgmem(&msg);
continue;
}
msg.hdr.attr |= MSG_DELETE;
msg.idx.attr = msg.hdr.attr;
if ((i = smb_putmsg(&smb, &msg)) != 0)
errormsg(WHERE, ERR_WRITE, smb.file, i, smb.last_error);
else
deleted++;
smb_unlockmsghdr(&smb, &msg);
smb_freemsgmem(&msg);
}
if (deleted && cfg.sys_misc & SM_DELEMAIL)
delmail(0, MAIL_YOUR);
smb_close(&smb);
if (mailmsgs)
free(mail);
lprintf(LOG_INFO, "Deleted %ld sent NetMail messages", deleted);
}
return true;
}