/* * transfugdrake * (c) 2001 Yves Duret * $Id$ */ /* 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. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* based on LIBOE 0.92 - STABLE Copyright (C) 2000 Stephan B. Nedregård (stephan@micropop.com) */ #include #include #include #include #define OE_CANNOTREAD 1 #define OE_NOTOEBOX 2 #define OE_POSITION 3 #define OE_NOBODY 4 #define OE_PANIC 5 #define SLASH '/' /* #define DEBUG -- uncomment to get some DEBUG output to stdout */ /* TABLE STRUCTURES -- tables store pointers to message headers and other tables also containing pointers to message headers and other tables -- */ struct oe_table_header { /* At the beginning of each table */ int self, /* Pointer to self (filepos) */ unknown1, /* Unknown */ list, /* Pointer to list */ next, /* Pointer to next */ unknown3, /* Unknown */ unknown4; /* Unknown */ }; typedef struct oe_table_header oe_table_header; struct oe_table_node { /* Actual table entries */ int message, /* Pointer to message | 0 */ list, /* Pointer to another table | 0 */ unknown; /* Unknown */ }; typedef struct oe_table_node oe_table_node; struct oe_list { /* Internal use only */ long pos; struct oe_list *next; }; typedef struct oe_list oe_list; /* MESSAGE STRUCTURES -- OE uses 16-byte segment headers inside the actual messages. These are meaningful, as described below, but were not very easy to hack correctly -- note that a message may be composed of segments located anywhere in the mailbox file, some times far from each other. */ struct oe_msg_segmentheader { int self, /* Pointer to self (filepos) */ increase, /* Increase to next segment header (not in msg, in file!) */ include, /* Number of bytes to include from this segment */ next, /* Pointer to next message segment (in msg) (filepos) */ usenet; /* Only used with usenet posts */ }; typedef struct oe_msg_segmentheader oe_msg_segmentheader; /* INTERAL STRUCTURES */ struct oe_internaldata{ void (*oput)(char*); FILE *oe; oe_list *used; int success, justheaders, failure; int errcode; struct stat *stat; }; typedef struct oe_internaldata oe_data; /* LIST OF USED TABLES */ void oe_posused(oe_data *data, long pos) { oe_list *n = malloc(sizeof(oe_list)); n->pos = pos; n->next = data->used; data->used = n; } int oe_isposused(oe_data *data, long pos) { oe_list *n = data->used; while (n!=NULL) { if (pos==n->pos) return 1; n = n->next; } return 0; } void oe_freeposused(oe_data *data) { oe_list *n; while (data->used!=NULL) {n=data->used->next; free(data->used); data->used=n;} } /* ACTUAL MESSAGE PARSER */ int oe_readmessage(oe_data *data, long pos, int newsarticle) { int segheadsize = sizeof(oe_msg_segmentheader)-4; /*+(newsarticle<<2);*/ oe_msg_segmentheader *sgm = malloc(sizeof(oe_msg_segmentheader)); char buff[16], *ss = malloc(2048), *s = ss; int nextsegment, endofsegment, i, headerwritten = 0; fseek(data->oe,pos, SEEK_SET); while (1) { fread(sgm,segheadsize,1,data->oe); if (pos!=sgm->self) { /* No body found*/ #ifdef DEBUG printf("- Fail reported at %.8x (%.8x)\n",pos,sgm->self); #endif free(sgm); free(ss); data->failure++; return OE_NOBODY; } pos+=segheadsize; nextsegment = pos+sgm->increase; endofsegment = pos+sgm->include; if (!headerwritten) { #ifdef DEBUG printf("%.8x : \n",pos-segheadsize); #endif data->oput("From mandrake@MandrakeLinux Mon Jun 11 10:00:00 2001\n"); headerwritten = 1; } while (posoe); for (i=0;i<16;i++,pos++) if ((posoput(ss); s=ss; } } } fseek(data->oe,sgm->next, SEEK_SET); pos = sgm->next; if (pos==0) break; } if (s!=ss) { strcpy(s,"\n"); data->oput(s); } data->oput("\n"); data->success++; free(sgm); free(ss); return 0; } /* PARSES MESSAGE HEADERS */ int oe_readmessageheader(oe_data *data, long pos) { int segheadsize = sizeof(oe_msg_segmentheader)-4; oe_msg_segmentheader *sgm; int self=1, msgpos = 0, newsarticle = 0; if (oe_isposused(data,pos)) return 0; else oe_posused(data,pos); fseek(data->oe,pos, SEEK_SET); sgm = malloc(sizeof(oe_msg_segmentheader)); fread(sgm,segheadsize,1,data->oe); if (pos!=sgm->self) { free(sgm); return OE_POSITION; /* ERROR */ } free(sgm); fread(&self,4,1,data->oe); self=1; while ((self & 0x7F)>0) { fread(&self,4,1,data->oe); if ((self & 0xFF) == 0x84) /* 0x80 = Set, 04 = Index */ if (msgpos==0) msgpos = self >> 8; if ((self & 0xFF) == 0x83) /* 0x80 = Set, 03 = News */ newsarticle = 1; } if (msgpos) oe_readmessage(data,msgpos,newsarticle); else { fread(&self,4,1,data->oe); fread(&msgpos,4,1,data->oe); if (oe_readmessage(data,msgpos,newsarticle)) { if (newsarticle) { data->justheaders++; data->failure--; } } } return 0; } /* PARSES MAILBOX TABLES */ int oe_readtable(oe_data *data, long pos) { oe_table_header thead; oe_table_node tnode; int quit = 0; if (oe_isposused(data,pos)) return 0; fseek(data->oe,pos, SEEK_SET); fread(&thead,sizeof(oe_table_header),1,data->oe); if (thead.self != pos) return OE_POSITION; oe_posused(data,pos); pos+=sizeof(oe_table_header); oe_readtable(data,thead.next); oe_readtable(data,thead.list); fseek(data->oe,pos, SEEK_SET); while (!quit) { fread(&tnode,sizeof(oe_table_node),1,data->oe); pos+=sizeof(oe_table_node); if ( (tnode.message > data->stat->st_size) && (tnode.list > data->stat->st_size) ) return 0xF0; /* PANIC */ if ( (tnode.message == tnode.list) && /* Neither message nor list==quit */ (tnode.message == 0) ) quit = 1; else { oe_readmessageheader(data,tnode.message); oe_readtable(data,tnode.list); } fseek(data->oe,pos, SEEK_SET); } return 0; } void oe_readdamaged(oe_data *data) { /* If nothing else works (needed this to get some mailboxes that even OE couldn't read to work. Should generally not be needed, but is nice to have in here */ long pos = 0x7C; int i,check, lastID; #ifdef DEBUG printf(" Trying to construct internal mailbox structure\n"); #endif fseek(data->oe,pos, SEEK_SET); fread(&pos,sizeof(int),1,data->oe); if (pos==0) return; /* No, sorry, didn't work */ fseek(data->oe,pos, SEEK_SET); fread(&i,sizeof(int),1,data->oe); if (i!=pos) return; /* Sorry */ fread(&pos,sizeof(int),1,data->oe); i+=pos+8; pos = i+4; fseek(data->oe,pos, SEEK_SET); #ifdef DEBUG printf(" Searching for %.8x\n",i); #endif lastID=0; while (posstat->st_size) { /* Read through file, notice markers, look for message (gen. 2BD4)*/ fread(&check,sizeof(int),1,data->oe); if (check==pos) lastID=pos; pos+=4; if ((check==i) && (lastID)) { #ifdef DEBUG printf("Trying possible table at %.8x\n",lastID); #endif oe_readtable(data,lastID); fseek(data->oe,pos, SEEK_SET); } } } void oe_readbox_oe4(oe_data *data) { long pos = 0x54, endpos=0, i; oe_msg_segmentheader *header=malloc(sizeof(oe_msg_segmentheader)); char *cb = malloc(4), *sfull = malloc(65536), *s = sfull; fseek(data->oe,pos, SEEK_SET); while (posstat->st_size) { fseek(data->oe,pos, SEEK_SET); fread(header,16,1,data->oe); data->oput("From mandrake@MandrakeLinux Mon Jun 11 10:00:00 2001\n"); endpos = pos + header->include; if (endpos>data->stat->st_size) endpos=data->stat->st_size; pos+=4; while (posoe); for (i=0;i<4;i++,pos++) if (*(cb+i)!=0x0d) { *s++ = *(cb+i); if (*(cb+i) == 0x0a) { *s = '\0'; data->oput(sfull); s = sfull; } } } data->success++; if (s!=sfull) { *s='\0'; data->oput(sfull); s=sfull; } data->oput("\n"); pos=endpos; } free(header); free(sfull); free(cb); } /* CALL THIS ONE */ oe_data* oe_readbox(char* filename,void (*oput)(char*)) { int signature[4], i; oe_data *data = malloc(sizeof(oe_data)); data->success=data->failure=data->justheaders=data->errcode=0; data->used = NULL; data->oput = oput; data->oe = fopen(filename,"rb"); if (data->oe==NULL) { fclose(data->oe); data->errcode = OE_CANNOTREAD; return data; } /* SECURITY (Yes, we need this, just in case) */ data->stat = malloc(sizeof(struct stat)); stat(filename,data->stat); /* SIGNATURE */ fread(&signature,16,1,data->oe); if ((signature[0]!=0xFE12ADCF) || /* OE 5 & OE 5 BETA SIGNATURE */ (signature[1]!=0x6F74FDC5) || (signature[2]!=0x11D1E366) || (signature[3]!=0xC0004E9A)) { if ((signature[0]==0x36464D4A) && (signature[1]==0x00010003)) /* OE4 SIGNATURE */ { oe_readbox_oe4(data); fclose(data->oe); free(data->stat); return data; } fclose(data->oe); free(data->stat); data->errcode = OE_NOTOEBOX; return data; } /* ACTUAL WORK */ i = 0x30; fseek(data->oe,i, SEEK_SET); fread(&i,4,1,data->oe); if (!i) i=0x1e254; i = oe_readtable(data,i); /* Reads the box */ if (i & 0xF0) { oe_readdamaged(data); data->errcode=OE_PANIC; } oe_freeposused(data); /* CLOSE DOWN */ fclose(data->oe); free(data->stat); return data; } #define buffsize 65536 /* Just a function to provide the same kind of stream for ordinary mailboxes. */ oe_data* oe_readmbox(char* filename,void (*oput)(char*)) { oe_data *data = malloc(sizeof(oe_data)); char *s = malloc(buffsize); data->success=data->failure=data->justheaders=0; data->used=NULL; data->oe=fopen(filename,"rb"); for (;;) { s=fgets(s,buffsize,data->oe); if (s==NULL) break; else oput(s); } fclose(data->oe); return data; } /****************************************/ FILE *mbox = NULL; char *filename = NULL, *fn; void msgandquit(int h) { if (h==0) printf("transfug_oe\nSyntax: transfug_oe [oe_mbox]*\n" "based on OE2MBX 1.21 (c) 2000 Stephan B. Nedregaard - stephan@micropop.com\n"); else if (h==1) printf("OE2MBX cannot run on this platform. Please consult the Web site at http://www.micropop.com/code/\n"); exit(h); } void fatal(char *s) { printf("Fatal error: %s\n\n",s); exit(1); } void writeit(char *s) { if (mbox==NULL) { mbox=fopen(fn,"w"); if(mbox==NULL) fatal("Cannot create output file"); } fprintf(mbox,"%s",s); } int main(int argc, char*argv[]) { int i; /* Handle errors, help and syntax */ if (argc<2) msgandquit(0); for (i=1;i %s\n",fn); j = (oe_data*) oe_readbox(argv[i],writeit); if (j!=NULL) { if (!j->success) printf(" No messages converted"); else printf(" %d messages converted",j->success); if (j->justheaders) printf(" (%d headers w/o bodies)",j->justheaders); if (j->failure) printf(" (%d messages failed)",j->failure); printf("\n"); } else printf(" Empty mailbox\n"); if (mbox!=NULL) fclose(mbox); mbox=NULL; free(filename); } return 0; }