/* Copyright (C) 2020 C. McEnroe * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "archive.h" #include "imap.h" bool exportFetch(FILE *imap, enum Atom tag, struct List threads) { struct List uids = {0}; listFlatten(&uids, threads); char path[PATH_MAX]; for (size_t i = uids.len - 1; i < uids.len; --i) { uint32_t uid = dataCheck(uids.ptr[i], Number).number; int error = 0 || access(pathUID(path, uid, "atom"), F_OK) || access(pathUID(path, uid, "html"), F_OK) || access(pathUID(path, uid, "mbox"), F_OK); if (!error) uids.ptr[i] = uids.ptr[--uids.len]; } if (!uids.len) { listFree(uids); return false; } fprintf(imap, "%s UID FETCH ", Atoms[tag]); for (size_t i = 0; i < uids.len; ++i) { fprintf(imap, "%s%" PRIu32, (i ? "," : ""), uids.ptr[i].number); } fprintf( imap, " (UID ENVELOPE BODYSTRUCTURE" " BODY[HEADER.FIELDS (" MBOX_HEADERS ")] BODY[TEXT])\r\n" ); return true; } static void exportEnvelope( uint32_t uid, struct Envelope *envelope, char *header, char *body ) { int error; FILE *file; char path[PATH_MAX]; pathUID(path, uid, "mbox"); file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); error = 0 || mboxFrom(file) || mboxHeader(file, header) || mboxBody(file, body) || fclose(file); if (error) err(EX_IOERR, "%s", path); char dest[PATH_MAX]; pathMessage(dest, envelope->messageID, "mbox"); unlink(dest); error = link(path, dest); if (error) err(EX_CANTCREAT, "%s", dest); pathUID(path, uid, "html"); file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); error = 0 || htmlMessageHead(file, envelope) || htmlMessageTail(file) || fclose(file); if (error) err(EX_IOERR, "%s", path); pathUID(path, uid, "atom"); file = fopen(path, "w"); if (!file) err(EX_CANTCREAT, "%s", path); error = 0 || atomEntryHead(file, envelope) || atomEntryTail(file) || fclose(file); if (error) err(EX_IOERR, "%s", path); } bool exportData(FILE *imap, enum Atom tag, struct List items) { uint32_t uid = 0; struct Envelope envelope = {0}; struct BodyPart structure = {0}; char *header = NULL; char *body = NULL; for (size_t i = 0; i + 1 < items.len; i += 2) { enum Atom name; if (items.ptr[i].type == Atom) { name = items.ptr[i].atom; } else if ( items.ptr[i].type == List && items.ptr[i].list.len && items.ptr[i].list.ptr[0].type == Atom ) { name = items.ptr[i].list.ptr[0].atom; } else { errx(EX_PROTOCOL, "invalid data item name"); } struct Data data = items.ptr[i + 1]; switch (name) { break; case AtomBody: i--; break; case AtomUID: uid = dataCheck(data, Number).number; break; case AtomEnvelope: parseEnvelope(&envelope, dataCheck(data, List).list); break; case AtomBodyStructure: parseBodyPart(&structure, dataCheck(data, List).list); break; case AtomHeaderFields: header = dataCheck(data, String).string; break; case AtomText: body = dataCheck(data, String).string; break; default:; } } if (!uid) errx(EX_PROTOCOL, "missing UID data item"); if (!envelope.subject) errx(EX_PROTOCOL, "missing ENVELOPE data item"); if (!header) errx(EX_PROTOCOL, "missing BODY[HEADER.FIELDS] data item"); if (!body) errx(EX_PROTOCOL, "missing BODY[TEXT] data item"); exportEnvelope(uid, &envelope, header, body); envelopeFree(envelope); bodyPartFree(structure); return false; }