1 |
/* |
2 |
* transfugdrake |
3 |
* (c) 2001 Yves Duret <yduret@mandrakesof.com> |
4 |
* $Id: transfug_oe.c 225151 2006-12-09 03:13:01Z pablo $ |
5 |
*/ |
6 |
|
7 |
/* This program is free software; you can redistribute it and/or modify |
8 |
it under the terms of the GNU General Public License as published by |
9 |
the Free Software Foundation; either version 2 of the License, or |
10 |
(at your option) any later version. |
11 |
|
12 |
This program is distributed in the hope that it will be useful, |
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
GNU General Public License for more details. |
16 |
|
17 |
You should have received a copy of the GNU General Public License |
18 |
along with this program; if not, write to the Free Software |
19 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 |
*/ |
21 |
|
22 |
/* based on LIBOE 0.92 - STABLE |
23 |
Copyright (C) 2000 Stephan B. NedregÄrd (stephan@micropop.com) */ |
24 |
|
25 |
#include <stdio.h> |
26 |
#include <stdlib.h> |
27 |
#include <string.h> |
28 |
#include <sys/stat.h> |
29 |
|
30 |
#define OE_CANNOTREAD 1 |
31 |
#define OE_NOTOEBOX 2 |
32 |
#define OE_POSITION 3 |
33 |
#define OE_NOBODY 4 |
34 |
#define OE_PANIC 5 |
35 |
|
36 |
#define SLASH '/' |
37 |
|
38 |
|
39 |
/* #define DEBUG -- uncomment to get some DEBUG output to stdout */ |
40 |
|
41 |
|
42 |
/* TABLE STRUCTURES |
43 |
-- tables store pointers to message headers and other tables also |
44 |
containing pointers to message headers and other tables -- */ |
45 |
|
46 |
struct oe_table_header { /* At the beginning of each table */ |
47 |
int self, /* Pointer to self (filepos) */ |
48 |
unknown1, /* Unknown */ |
49 |
list, /* Pointer to list */ |
50 |
next, /* Pointer to next */ |
51 |
unknown3, /* Unknown */ |
52 |
unknown4; /* Unknown */ |
53 |
}; |
54 |
typedef struct oe_table_header oe_table_header; |
55 |
|
56 |
struct oe_table_node { /* Actual table entries */ |
57 |
int message, /* Pointer to message | 0 */ |
58 |
list, /* Pointer to another table | 0 */ |
59 |
unknown; /* Unknown */ |
60 |
}; |
61 |
typedef struct oe_table_node oe_table_node; |
62 |
|
63 |
struct oe_list { /* Internal use only */ |
64 |
long pos; |
65 |
struct oe_list *next; |
66 |
}; |
67 |
typedef struct oe_list oe_list; |
68 |
|
69 |
|
70 |
|
71 |
/* MESSAGE STRUCTURES |
72 |
-- OE uses 16-byte segment headers inside the actual messages. These |
73 |
are meaningful, as described below, but were not very easy to hack |
74 |
correctly -- note that a message may be composed of segments located |
75 |
anywhere in the mailbox file, some times far from each other. */ |
76 |
|
77 |
struct oe_msg_segmentheader { |
78 |
int self, /* Pointer to self (filepos) */ |
79 |
increase, /* Increase to next segment header (not in msg, in file!) */ |
80 |
include, /* Number of bytes to include from this segment */ |
81 |
next, /* Pointer to next message segment (in msg) (filepos) */ |
82 |
usenet; /* Only used with usenet posts */ |
83 |
}; |
84 |
typedef struct oe_msg_segmentheader oe_msg_segmentheader; |
85 |
|
86 |
|
87 |
|
88 |
|
89 |
/* INTERAL STRUCTURES */ |
90 |
struct oe_internaldata{ |
91 |
void (*oput)(char*); |
92 |
FILE *oe; |
93 |
oe_list *used; |
94 |
int success, justheaders, failure; |
95 |
int errcode; |
96 |
struct stat *stat; |
97 |
}; |
98 |
typedef struct oe_internaldata oe_data; |
99 |
|
100 |
|
101 |
|
102 |
/* LIST OF USED TABLES */ |
103 |
|
104 |
void oe_posused(oe_data *data, long pos) { |
105 |
oe_list *n = malloc(sizeof(oe_list)); |
106 |
n->pos = pos; |
107 |
n->next = data->used; |
108 |
data->used = n; |
109 |
} |
110 |
|
111 |
int oe_isposused(oe_data *data, long pos) { |
112 |
oe_list *n = data->used; |
113 |
while (n!=NULL) { |
114 |
if (pos==n->pos) return 1; |
115 |
n = n->next; |
116 |
} |
117 |
return 0; |
118 |
} |
119 |
|
120 |
void oe_freeposused(oe_data *data) { |
121 |
oe_list *n; |
122 |
while (data->used!=NULL) {n=data->used->next; free(data->used); data->used=n;} |
123 |
} |
124 |
|
125 |
|
126 |
/* ACTUAL MESSAGE PARSER */ |
127 |
|
128 |
int oe_readmessage(oe_data *data, |
129 |
long pos, |
130 |
int newsarticle) { |
131 |
int segheadsize = sizeof(oe_msg_segmentheader)-4; /*+(newsarticle<<2);*/ |
132 |
oe_msg_segmentheader *sgm = malloc(sizeof(oe_msg_segmentheader)); |
133 |
char buff[16], *ss = malloc(2048), *s = ss; |
134 |
int nextsegment, endofsegment, i, headerwritten = 0; |
135 |
fseek(data->oe,pos, SEEK_SET); |
136 |
while (1) { |
137 |
fread(sgm,segheadsize,1,data->oe); |
138 |
if (pos!=sgm->self) { /* No body found*/ |
139 |
#ifdef DEBUG |
140 |
printf("- Fail reported at %.8x (%.8x)\n",pos,sgm->self); |
141 |
#endif |
142 |
free(sgm); |
143 |
free(ss); |
144 |
data->failure++; |
145 |
return OE_NOBODY; |
146 |
} |
147 |
pos+=segheadsize; |
148 |
nextsegment = pos+sgm->increase; |
149 |
endofsegment = pos+sgm->include; |
150 |
if (!headerwritten) { |
151 |
#ifdef DEBUG |
152 |
printf("%.8x : \n",pos-segheadsize); |
153 |
#endif |
154 |
data->oput("From mandrake@MandrakeLinux Mon Jun 11 10:00:00 2001\n"); |
155 |
headerwritten = 1; |
156 |
} |
157 |
while (pos<endofsegment) { |
158 |
fread(&buff,1,16,data->oe); |
159 |
for (i=0;i<16;i++,pos++) |
160 |
if ((pos<endofsegment) && (buff[i]!=0x0d)) { /* rm extra DOS newline */ |
161 |
*(s++)=buff[i]; |
162 |
if (buff[i]==0x0a) { *s='\0'; data->oput(ss); s=ss; } |
163 |
} |
164 |
} |
165 |
fseek(data->oe,sgm->next, SEEK_SET); |
166 |
pos = sgm->next; |
167 |
if (pos==0) break; |
168 |
} |
169 |
if (s!=ss) { |
170 |
strcpy(s,"\n"); |
171 |
data->oput(s); |
172 |
} |
173 |
data->oput("\n"); |
174 |
|
175 |
data->success++; |
176 |
free(sgm); |
177 |
free(ss); |
178 |
return 0; |
179 |
} |
180 |
|
181 |
|
182 |
/* PARSES MESSAGE HEADERS */ |
183 |
|
184 |
int oe_readmessageheader(oe_data *data, long pos) { |
185 |
int segheadsize = sizeof(oe_msg_segmentheader)-4; |
186 |
oe_msg_segmentheader *sgm; |
187 |
int self=1, msgpos = 0, newsarticle = 0; |
188 |
|
189 |
if (oe_isposused(data,pos)) return 0; else oe_posused(data,pos); |
190 |
fseek(data->oe,pos, SEEK_SET); |
191 |
sgm = malloc(sizeof(oe_msg_segmentheader)); |
192 |
fread(sgm,segheadsize,1,data->oe); |
193 |
if (pos!=sgm->self) { free(sgm); return OE_POSITION; /* ERROR */ } |
194 |
free(sgm); |
195 |
|
196 |
fread(&self,4,1,data->oe); self=1; |
197 |
while ((self & 0x7F)>0) { |
198 |
fread(&self,4,1,data->oe); |
199 |
if ((self & 0xFF) == 0x84) /* 0x80 = Set, 04 = Index */ |
200 |
if (msgpos==0) |
201 |
msgpos = self >> 8; |
202 |
if ((self & 0xFF) == 0x83) /* 0x80 = Set, 03 = News */ |
203 |
newsarticle = 1; |
204 |
} |
205 |
if (msgpos) oe_readmessage(data,msgpos,newsarticle); else { |
206 |
fread(&self,4,1,data->oe); |
207 |
fread(&msgpos,4,1,data->oe); |
208 |
if (oe_readmessage(data,msgpos,newsarticle)) { |
209 |
if (newsarticle) { |
210 |
data->justheaders++; |
211 |
data->failure--; |
212 |
} |
213 |
} |
214 |
} |
215 |
return 0; |
216 |
} |
217 |
|
218 |
|
219 |
/* PARSES MAILBOX TABLES */ |
220 |
|
221 |
int oe_readtable(oe_data *data, long pos) { |
222 |
oe_table_header thead; |
223 |
oe_table_node tnode; |
224 |
int quit = 0; |
225 |
|
226 |
if (oe_isposused(data,pos)) return 0; |
227 |
|
228 |
fseek(data->oe,pos, SEEK_SET); |
229 |
|
230 |
fread(&thead,sizeof(oe_table_header),1,data->oe); |
231 |
if (thead.self != pos) return OE_POSITION; |
232 |
oe_posused(data,pos); |
233 |
pos+=sizeof(oe_table_header); |
234 |
|
235 |
oe_readtable(data,thead.next); |
236 |
oe_readtable(data,thead.list); |
237 |
fseek(data->oe,pos, SEEK_SET); |
238 |
|
239 |
while (!quit) { |
240 |
fread(&tnode,sizeof(oe_table_node),1,data->oe); |
241 |
pos+=sizeof(oe_table_node); |
242 |
if ( (tnode.message > data->stat->st_size) && |
243 |
(tnode.list > data->stat->st_size) ) |
244 |
return 0xF0; /* PANIC */ |
245 |
if ( (tnode.message == tnode.list) && /* Neither message nor list==quit */ |
246 |
(tnode.message == 0) ) quit = 1; else { |
247 |
oe_readmessageheader(data,tnode.message); |
248 |
oe_readtable(data,tnode.list); |
249 |
} |
250 |
fseek(data->oe,pos, SEEK_SET); |
251 |
} |
252 |
|
253 |
return 0; |
254 |
} |
255 |
|
256 |
void oe_readdamaged(oe_data *data) { |
257 |
/* If nothing else works (needed this to get some mailboxes |
258 |
that even OE couldn't read to work. Should generally not |
259 |
be needed, but is nice to have in here */ |
260 |
long pos = 0x7C; |
261 |
int i,check, lastID; |
262 |
#ifdef DEBUG |
263 |
printf(" Trying to construct internal mailbox structure\n"); |
264 |
#endif |
265 |
fseek(data->oe,pos, SEEK_SET); |
266 |
fread(&pos,sizeof(int),1,data->oe); |
267 |
if (pos==0) return; /* No, sorry, didn't work */ |
268 |
fseek(data->oe,pos, SEEK_SET); |
269 |
fread(&i,sizeof(int),1,data->oe); |
270 |
if (i!=pos) return; /* Sorry */ |
271 |
fread(&pos,sizeof(int),1,data->oe); |
272 |
i+=pos+8; |
273 |
pos = i+4; |
274 |
fseek(data->oe,pos, SEEK_SET); |
275 |
#ifdef DEBUG |
276 |
printf(" Searching for %.8x\n",i); |
277 |
#endif |
278 |
lastID=0; |
279 |
while (pos<data->stat->st_size) { |
280 |
/* Read through file, notice markers, look for message (gen. 2BD4)*/ |
281 |
fread(&check,sizeof(int),1,data->oe); |
282 |
if (check==pos) lastID=pos; |
283 |
pos+=4; |
284 |
if ((check==i) && (lastID)) { |
285 |
#ifdef DEBUG |
286 |
printf("Trying possible table at %.8x\n",lastID); |
287 |
#endif |
288 |
oe_readtable(data,lastID); |
289 |
fseek(data->oe,pos, SEEK_SET); |
290 |
} |
291 |
} |
292 |
} |
293 |
|
294 |
void oe_readbox_oe4(oe_data *data) { |
295 |
long pos = 0x54, endpos=0, i; |
296 |
oe_msg_segmentheader *header=malloc(sizeof(oe_msg_segmentheader)); |
297 |
char *cb = malloc(4), *sfull = malloc(65536), *s = sfull; |
298 |
fseek(data->oe,pos, SEEK_SET); |
299 |
while (pos<data->stat->st_size) { |
300 |
fseek(data->oe,pos, SEEK_SET); |
301 |
fread(header,16,1,data->oe); |
302 |
data->oput("From mandrake@MandrakeLinux Mon Jun 11 10:00:00 2001\n"); |
303 |
endpos = pos + header->include; |
304 |
if (endpos>data->stat->st_size) endpos=data->stat->st_size; |
305 |
pos+=4; |
306 |
while (pos<endpos) { |
307 |
fread(cb,1,4,data->oe); |
308 |
for (i=0;i<4;i++,pos++) |
309 |
if (*(cb+i)!=0x0d) { |
310 |
*s++ = *(cb+i); |
311 |
if (*(cb+i) == 0x0a) { |
312 |
*s = '\0'; |
313 |
data->oput(sfull); |
314 |
s = sfull; |
315 |
} |
316 |
} |
317 |
} |
318 |
data->success++; |
319 |
if (s!=sfull) { *s='\0'; data->oput(sfull); s=sfull; } |
320 |
data->oput("\n"); |
321 |
pos=endpos; |
322 |
} |
323 |
free(header); |
324 |
free(sfull); |
325 |
free(cb); |
326 |
} |
327 |
|
328 |
/* CALL THIS ONE */ |
329 |
|
330 |
oe_data* oe_readbox(char* filename,void (*oput)(char*)) { |
331 |
int signature[4], i; |
332 |
oe_data *data = malloc(sizeof(oe_data)); |
333 |
data->success=data->failure=data->justheaders=data->errcode=0; |
334 |
data->used = NULL; |
335 |
data->oput = oput; |
336 |
data->oe = fopen(filename,"rb"); |
337 |
if (data->oe==NULL) { |
338 |
fclose(data->oe); |
339 |
data->errcode = OE_CANNOTREAD; |
340 |
return data; |
341 |
} |
342 |
|
343 |
/* SECURITY (Yes, we need this, just in case) */ |
344 |
data->stat = malloc(sizeof(struct stat)); |
345 |
stat(filename,data->stat); |
346 |
|
347 |
/* SIGNATURE */ |
348 |
fread(&signature,16,1,data->oe); |
349 |
if ((signature[0]!=0xFE12ADCF) || /* OE 5 & OE 5 BETA SIGNATURE */ |
350 |
(signature[1]!=0x6F74FDC5) || |
351 |
(signature[2]!=0x11D1E366) || |
352 |
(signature[3]!=0xC0004E9A)) { |
353 |
if ((signature[0]==0x36464D4A) && |
354 |
(signature[1]==0x00010003)) /* OE4 SIGNATURE */ { |
355 |
oe_readbox_oe4(data); |
356 |
fclose(data->oe); |
357 |
free(data->stat); |
358 |
return data; |
359 |
} |
360 |
fclose(data->oe); |
361 |
free(data->stat); |
362 |
data->errcode = OE_NOTOEBOX; |
363 |
return data; |
364 |
} |
365 |
|
366 |
/* ACTUAL WORK */ |
367 |
i = 0x30; |
368 |
fseek(data->oe,i, SEEK_SET); |
369 |
fread(&i,4,1,data->oe); |
370 |
if (!i) i=0x1e254; |
371 |
i = oe_readtable(data,i); /* Reads the box */ |
372 |
if (i & 0xF0) { |
373 |
oe_readdamaged(data); |
374 |
data->errcode=OE_PANIC; |
375 |
} |
376 |
oe_freeposused(data); |
377 |
|
378 |
/* CLOSE DOWN */ |
379 |
fclose(data->oe); |
380 |
free(data->stat); |
381 |
return data; |
382 |
} |
383 |
|
384 |
#define buffsize 65536 |
385 |
|
386 |
/* Just a function to provide the same kind of stream |
387 |
for ordinary mailboxes. */ |
388 |
oe_data* oe_readmbox(char* filename,void (*oput)(char*)) { |
389 |
oe_data *data = malloc(sizeof(oe_data)); |
390 |
char *s = malloc(buffsize); |
391 |
data->success=data->failure=data->justheaders=0; |
392 |
data->used=NULL; |
393 |
data->oe=fopen(filename,"rb"); |
394 |
for (;;) { |
395 |
s=fgets(s,buffsize,data->oe); |
396 |
if (s==NULL) break; else oput(s); |
397 |
} |
398 |
fclose(data->oe); |
399 |
return data; |
400 |
} |
401 |
|
402 |
/****************************************/ |
403 |
|
404 |
FILE *mbox = NULL; |
405 |
char *filename = NULL, *fn; |
406 |
|
407 |
void msgandquit(int h) { |
408 |
if (h==0) |
409 |
printf("transfug_oe\nSyntax: transfug_oe [oe_mbox]*\n" |
410 |
"based on OE2MBX 1.21 (c) 2000 Stephan B. Nedregaard - stephan@micropop.com\n"); |
411 |
else if (h==1) |
412 |
printf("OE2MBX cannot run on this platform. Please consult the Web site at http://www.micropop.com/code/\n"); |
413 |
exit(h); |
414 |
} |
415 |
|
416 |
void fatal(char *s) { |
417 |
printf("Fatal error: %s\n\n",s); |
418 |
exit(1); |
419 |
} |
420 |
|
421 |
void writeit(char *s) { |
422 |
if (mbox==NULL) { |
423 |
mbox=fopen(fn,"w"); |
424 |
if(mbox==NULL) fatal("Cannot create output file"); |
425 |
} |
426 |
fprintf(mbox,"%s",s); |
427 |
} |
428 |
|
429 |
int main(int argc, char*argv[]) { |
430 |
int i; |
431 |
oe_data *j; |
432 |
|
433 |
/* Handle errors, help and syntax */ |
434 |
if (argc<3) msgandquit(0); |
435 |
|
436 |
/* Process mailboxes */ |
437 |
printf("Converting %s...\n",argv[1]); |
438 |
fn = argv[2]; |
439 |
if (*fn==SLASH) fn++; |
440 |
printf(" => %s\n",fn); |
441 |
j = (oe_data*) oe_readbox(argv[1],writeit); |
442 |
if (j!=NULL) { |
443 |
if (!j->success) printf(" No messages converted"); else |
444 |
printf(" %d messages converted",j->success); |
445 |
if (j->justheaders) printf(" (%d headers w/o bodies)",j->justheaders); |
446 |
if (j->failure) printf(" (%d messages failed)",j->failure); |
447 |
printf("\n"); |
448 |
} else printf(" Empty mailbox\n"); |
449 |
if (mbox!=NULL) fclose(mbox); |
450 |
mbox=NULL; |
451 |
return 0; |
452 |
} |