/* 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; }