|
|
1.1 root 1: /* FIDO2SMB.C */
2:
3: /* Converts FidoNet FTSC-1 (*.MSG) message base to SMB format */
4:
5: /* The intention of this source code is an example of how to use the SMBLIB */
6: /* library functions to access an SMB format message base. */
7:
8: /* This program and source code are freeware. May be used in part or whole */
9: /* for any purpose without consent or notification of Digital Dynamics. */
10:
11: /* Digital Dynamics does request that developers that release products that */
12: /* support the SMB format notify Digital Dynamics so the implementation */
13: /* and contact chapters in the technical specification may be updated. */
14:
15: #include "smblib.h"
16: #include "crc32.h"
17: #include <dos.h>
18: /* Attribute bits for fido msg header */
19: #define FIDO_PRIVATE (1<<0) /* Private message */
20: #define FIDO_CRASH (1<<1) /* Crash-mail (send immediately) */
21: #define FIDO_RECV (1<<2) /* Received successfully */
22: #define FIDO_SENT (1<<3) /* Sent successfully */
23: #define FIDO_FILE (1<<4) /* File attached */
24: #define FIDO_INTRANS (1<<5) /* In transit */
25: #define FIDO_ORPHAN (1<<6) /* Orphan */
26: #define FIDO_KILLSENT (1<<7) /* Kill it after sending it */
27: #define FIDO_LOCAL (1<<8) /* Created locally - on this system */
28: #define FIDO_HOLD (1<<9) /* Hold - don't send it yet */
29: #define FIDO_FREQ (1<<11) /* File request */
30: #define FIDO_RRREQ (1<<12) /* Return receipt request */
31: #define FIDO_RR (1<<13) /* This is a return receipt */
32: #define FIDO_AUDIT (1<<14) /* Audit request */
33: #define FIDO_FUPREQ (1<<15) /* File update request */
34:
35: typedef struct { /* FidoNet msg header */
36: uchar from[36], /* From user */
37: to[36], /* To user */
38: subj[72], /* Message title */
39: time[20]; /* Time in goof-ball ASCII format */
40: short read, /* Times read */
41: destnode, /* Destination node */
42: orignode, /* Origin node */
43: cost, /* Cost in pennies */
44: orignet, /* Origin net */
45: destnet, /* Destination net */
46: destzone, /* Destination zone */
47: origzone, /* Origin zone */
48: destpoint, /* Destination point */
49: origpoint, /* Origin point */
50: re, /* Message number regarding */
51: attr, /* Attributes - see FIDO_* */
52: next; /* Next message number in stream */
53: } fmsghdr_t;
54:
55: /******************************************/
56: /* CRC-16 routines required for SMB index */
57: /******************************************/
58:
59: /****************************************************************************/
60: /* Updates 16-bit "rcrc" with character 'ch' */
61: /****************************************************************************/
62: void ucrc16(uchar ch, ushort *rcrc) {
63: ushort i, cy;
64: uchar nch=ch;
65:
66: for (i=0; i<8; i++) {
67: cy=*rcrc & 0x8000;
68: *rcrc<<=1;
69: if (nch & 0x80) *rcrc |= 1;
70: nch<<=1;
71: if (cy) *rcrc ^= 0x1021; }
72: }
73:
74: /****************************************************************************/
75: /* Returns 16-crc of string (not counting terminating NULL) */
76: /****************************************************************************/
77: ushort crc16(char *str)
78: {
79: int i=0;
80: ushort crc=0;
81:
82: ucrc16(0,&crc);
83: while(str[i])
84: ucrc16(str[i++],&crc);
85: ucrc16(0,&crc);
86: ucrc16(0,&crc);
87: return(crc);
88: }
89:
90: /****************************************************************************/
91: /* Truncates white-space chars off end of 'str' and terminates at first tab */
92: /****************************************************************************/
93: void truncsp(char *str)
94: {
95: char c;
96:
97: str[strcspn(str,"\t")]=0;
98: c=strlen(str);
99: while(c && (uchar)str[c-1]<=' ') c--;
100: str[c]=0;
101: }
102:
103: /****************************************************************************/
104: /* Returns the length of the file in 'filespec' */
105: /****************************************************************************/
106: long flength(char *filespec)
107: {
108: struct ffblk f;
109:
110: if(findfirst(filespec,&f,0)==0)
111: return(f.ff_fsize);
112: return(-1L);
113: }
114:
115: /****************************************************************************/
116: /* Returns the FidoNet address kept in str as ASCII. */
117: /****************************************************************************/
118: fidoaddr_t atofaddr(char *str)
119: {
120: char *p;
121: fidoaddr_t addr;
122:
123: addr.zone=addr.net=addr.node=addr.point=0;
124: if((p=strchr(str,':'))!=NULL) {
125: addr.zone=atoi(str);
126: addr.net=atoi(p+1); }
127: else {
128: addr.zone=1;
129: addr.net=atoi(str); }
130: if(!addr.zone) /* no such thing as zone 0 */
131: addr.zone=1;
132: if((p=strchr(str,'/'))!=NULL)
133: addr.node=atoi(p+1);
134: else {
135: addr.net=1;
136: addr.node=atoi(str); }
137: if((p=strchr(str,'.'))!=NULL)
138: addr.point=atoi(p+1);
139: return(addr);
140: }
141:
142: /****************************************************************************/
143: /* Converts goofy FidoNet time format into Unix format */
144: /****************************************************************************/
145: time_t fmsgtime(char *str)
146: {
147: char month[4];
148: struct date date;
149: struct time t;
150:
151: if(isdigit(str[1])) { /* Regular format: "01 Jan 86 02:34:56" */
152: date.da_day=atoi(str);
153: sprintf(month,"%3.3s",str+3);
154: if(!stricmp(month,"jan"))
155: date.da_mon=1;
156: else if(!stricmp(month,"feb"))
157: date.da_mon=2;
158: else if(!stricmp(month,"mar"))
159: date.da_mon=3;
160: else if(!stricmp(month,"apr"))
161: date.da_mon=4;
162: else if(!stricmp(month,"may"))
163: date.da_mon=5;
164: else if(!stricmp(month,"jun"))
165: date.da_mon=6;
166: else if(!stricmp(month,"jul"))
167: date.da_mon=7;
168: else if(!stricmp(month,"aug"))
169: date.da_mon=8;
170: else if(!stricmp(month,"sep"))
171: date.da_mon=9;
172: else if(!stricmp(month,"oct"))
173: date.da_mon=10;
174: else if(!stricmp(month,"nov"))
175: date.da_mon=11;
176: else
177: date.da_mon=12;
178: date.da_year=1900+atoi(str+7);
179: t.ti_hour=atoi(str+11);
180: t.ti_min=atoi(str+14);
181: t.ti_sec=atoi(str+17); }
182:
183: else { /* SEAdog format: "Mon 1 Jan 86 02:34" */
184: date.da_day=atoi(str+4);
185: sprintf(month,"%3.3s",str+7);
186: if(!stricmp(month,"jan"))
187: date.da_mon=1;
188: else if(!stricmp(month,"feb"))
189: date.da_mon=2;
190: else if(!stricmp(month,"mar"))
191: date.da_mon=3;
192: else if(!stricmp(month,"apr"))
193: date.da_mon=4;
194: else if(!stricmp(month,"may"))
195: date.da_mon=5;
196: else if(!stricmp(month,"jun"))
197: date.da_mon=6;
198: else if(!stricmp(month,"jul"))
199: date.da_mon=7;
200: else if(!stricmp(month,"aug"))
201: date.da_mon=8;
202: else if(!stricmp(month,"sep"))
203: date.da_mon=9;
204: else if(!stricmp(month,"oct"))
205: date.da_mon=10;
206: else if(!stricmp(month,"nov"))
207: date.da_mon=11;
208: else
209: date.da_mon=12;
210: date.da_year=1900+atoi(str+11);
211: t.ti_hour=atoi(str+14);
212: t.ti_min=atoi(str+17);
213: t.ti_sec=0; }
214: return(dostounix(&date,&t));
215: }
216:
217: /****************************************************************************/
218: /* Entry point - if you didn't know that, maybe you shouldn't be reading :) */
219: /****************************************************************************/
220: int main(int argc, char **argv)
221: {
222: uchar *p,str[128],*fbuf,*sbody,*stail,ch,done;
223: ushort xlat,net;
224: int i,j,file,col,cr,esc,orig,last,msgs,found;
225: ulong l,m,length,bodylen,taillen,crc;
226: struct ffblk ff;
227: smbmsg_t msg;
228: smbstatus_t status;
229: fmsghdr_t fmsghdr;
230: fidoaddr_t destaddr,origaddr,faddr;
231:
232: if(argc<3) {
233: printf("usage: fido2smb <fido_dir> <smb_name>\r\n");
234: exit(1); }
235:
236: strcpy(smb_file,argv[2]);
237: strupr(smb_file);
238:
239: smb_open(10);
240: if(!filelength(fileno(shd_fp)))
241: smb_create(2000,2000,0,0,10);
242:
243: smb_getstatus(&status); // Initialized for first call to smb_addcrc()
244:
245: /*********************************************/
246: /* Get the total number of .MSG files in dir */
247: /*********************************************/
248: printf("\nCounting messages...");
249: sprintf(str,"%s\\*.MSG",argv[1]);
250: last=findfirst(str,&ff,0);
251: for(msgs=0;!last;msgs++)
252: last=findnext(&ff);
253: printf("\n%u messages.\n",msgs);
254:
255: /******************************************/
256: /* Convert in sequence, starting at 1.MSG */
257: /******************************************/
258: for(i=1,found=0;found<msgs && i<2000;i++) {
259: sprintf(str,"%s\\%u.MSG",argv[1],i);
260: if((file=open(str,O_RDONLY|O_BINARY))==-1)
261: continue;
262: found++;
263: strupr(str);
264: printf("%s\n",str);
265: read(file,&fmsghdr,sizeof(fmsghdr_t));
266: memset(&msg,0,sizeof(smbmsg_t));
267: memcpy(msg.hdr.id,"SHD\x1a",4);
268: msg.hdr.version=SMB_VERSION;
269: if(fmsghdr.attr&FIDO_PRIVATE)
270: msg.idx.attr|=MSG_PRIVATE;
271: msg.hdr.attr=msg.idx.attr;
272:
273: msg.hdr.when_imported.time=time(NULL);
274: msg.hdr.when_written.time=fmsgtime(fmsghdr.time);
275:
276: origaddr.zone=fmsghdr.origzone; /* only valid if NetMail */
277: origaddr.net=fmsghdr.orignet;
278: origaddr.node=fmsghdr.orignode;
279: origaddr.point=fmsghdr.origpoint;
280:
281: destaddr.zone=fmsghdr.destzone; /* only valid if NetMail */
282: destaddr.net=fmsghdr.destnet;
283: destaddr.node=fmsghdr.destnode;
284: destaddr.point=fmsghdr.destpoint;
285:
286: smb_hfield(&msg,SENDER,strlen(fmsghdr.from),fmsghdr.from);
287: strlwr(fmsghdr.from);
288: msg.idx.from=crc16(fmsghdr.from);
289:
290: smb_hfield(&msg,RECIPIENT,strlen(fmsghdr.to),fmsghdr.to);
291: strlwr(fmsghdr.to);
292: msg.idx.to=crc16(fmsghdr.to);
293:
294: smb_hfield(&msg,SUBJECT,strlen(fmsghdr.subj),fmsghdr.subj);
295: strlwr(fmsghdr.subj);
296: msg.idx.subj=crc16(fmsghdr.subj);
297:
298: length=filelength(file)-sizeof(fmsghdr_t);
299: if((fbuf=(char *)MALLOC(length))==NULL) {
300: printf("alloc error\n");
301: exit(1); }
302: if((sbody=(char *)MALLOC(length*2L))==NULL) {
303: printf("alloc error\n");
304: exit(1); }
305: if((stail=(char *)MALLOC(length))==NULL) {
306: printf("alloc error\n");
307: exit(1); }
308: read(file,fbuf,length);
309: close(file);
310:
311: for(col=l=esc=done=bodylen=taillen=orig=0,cr=1;l<length;l++) {
312: ch=fbuf[l];
313: if(ch==1 && cr) { /* kludge line */
314:
315: if(!strncmp(fbuf+l+1,"TOPT ",5))
316: destaddr.point=atoi(fbuf+l+6);
317:
318: else if(!strncmp(fbuf+l+1,"FMPT ",5))
319: origaddr.point=atoi(fbuf+l+6);
320:
321: else if(!strncmp(fbuf+l+1,"INTL ",5)) {
322: faddr=atofaddr(fbuf+l+6);
323: destaddr.zone=faddr.zone;
324: destaddr.net=faddr.net;
325: destaddr.node=faddr.node;
326: l+=6;
327: while(l<length && fbuf[l]!=SP) l++;
328: faddr=atofaddr(fbuf+l+1);
329: origaddr.zone=faddr.zone;
330: origaddr.net=faddr.net;
331: origaddr.node=faddr.node; }
332:
333: else if(!strncmp(fbuf+l+1,"MSGID:",6)) {
334: l+=7;
335: while(l<length && fbuf[l]<=SP) l++;
336: m=l;
337: while(m<length && fbuf[m]!=CR) m++;
338: while(m && fbuf[m-1]<=SP) m--;
339: if(m>l)
340: smb_hfield(&msg,FIDOMSGID,m-l,fbuf+l); }
341:
342: else if(!strncmp(fbuf+l+1,"REPLY:",6)) {
343: l+=7;
344: while(l<length && fbuf[l]<=SP) l++;
345: m=l;
346: while(m<length && fbuf[m]!=CR) m++;
347: while(m && fbuf[m-1]<=SP) m--;
348: if(m>l)
349: smb_hfield(&msg,FIDOREPLYID,m-l,fbuf+l); }
350:
351: else if(!strncmp(fbuf+l+1,"FLAGS:",6)) {
352: l+=7;
353: while(l<length && fbuf[l]<=SP) l++;
354: m=l;
355: while(m<length && fbuf[m]!=CR) m++;
356: while(m && fbuf[m-1]<=SP) m--;
357: if(m>l)
358: smb_hfield(&msg,FIDOFLAGS,m-l,fbuf+l); }
359:
360: else if(!strncmp(fbuf+l+1,"PATH:",5)) {
361: l+=6;
362: while(l<length && fbuf[l]<=SP) l++;
363: m=l;
364: while(m<length && fbuf[m]!=CR) m++;
365: while(m && fbuf[m-1]<=SP) m--;
366: if(m>l)
367: smb_hfield(&msg,FIDOPATH,m-l,fbuf+l); }
368:
369: else if(!strncmp(fbuf+l+1,"PID:",4)) {
370: l+=5;
371: while(l<length && fbuf[l]<=SP) l++;
372: m=l;
373: while(m<length && fbuf[m]!=CR) m++;
374: while(m && fbuf[m-1]<=SP) m--;
375: if(m>l)
376: smb_hfield(&msg,FIDOPID,m-l,fbuf+l); }
377:
378: else { /* Unknown kludge line */
379: while(l<length && fbuf[l]<=SP) l++;
380: m=l;
381: while(m<length && fbuf[m]!=CR) m++;
382: while(m && fbuf[m-1]<=SP) m--;
383: if(m>l)
384: smb_hfield(&msg,FIDOCTRL,m-l,fbuf+l); }
385:
386: while(l<length && fbuf[l]!=CR) l++;
387: continue; }
388:
389: if(ch!=LF && ch!=0x8d) { /* ignore LF and soft CRs */
390: if(cr && (!strncmp((char *)fbuf+l,"--- ",4)
391: || !strncmp((char *)fbuf+l,"---\r",4)))
392: done=1; /* tear line and down go into tail */
393: if(done && cr && !strncmp(fbuf+l,"SEEN-BY:",8)) {
394: l+=8;
395: while(l<length && fbuf[l]<=SP) l++;
396: m=l;
397: while(m<length && fbuf[m]!=CR) m++;
398: while(m && fbuf[m-1]<=SP) m--;
399: if(m>l)
400: smb_hfield(&msg,FIDOSEENBY,m-l,fbuf+l);
401: while(l<length && fbuf[l]!=CR) l++;
402: continue; } /* skip the CR */
403: if(done)
404: stail[taillen++]=ch;
405: else
406: sbody[bodylen++]=ch;
407: col++;
408: if(ch==CR) {
409: cr=1;
410: col=0;
411: if(done)
412: stail[taillen++]=LF;
413: else
414: sbody[bodylen++]=LF; }
415: else {
416: cr=0;
417: if(col==1 && !strncmp((char *)fbuf+l," * Origin: ",11)) {
418: p=strchr(fbuf+l+11,CR); /* find carriage return */
419: while(p && *p!='(') p--; /* rewind to '(' */
420: if(p)
421: origaddr=atofaddr(p+1); /* get orig address */
422: orig=done=1; }
423: if(done)
424: continue;
425:
426: if(ch==ESC) esc=1; /* ANSI codes */
427: if(ch==SP && col>40 && !esc) { /* word wrap */
428: for(m=l+1;m<length;m++) /* find next space */
429: if(fbuf[m]<=SP)
430: break;
431: if(m<length && m-l>80-col) { /* if it's beyond the eol */
432: sbody[bodylen++]=CR;
433: sbody[bodylen++]=LF;
434: col=0; } }
435: } } }
436:
437: if(bodylen>=2 && sbody[bodylen-2]==CR && sbody[bodylen-1]==LF)
438: bodylen-=2; /* remove last CRLF if present */
439:
440: for(l=0,crc=0xffffffff;l<bodylen;l++)
441: crc=ucrc32(sbody[l],crc);
442: crc=~crc;
443:
444: j=smb_addcrc(status.max_crcs,crc,10);
445: if(j) {
446: if(j==1) {
447: printf("\nDuplicate message\n");
448: smb_freemsgmem(msg);
449: FREE(fbuf);
450: FREE(sbody);
451: FREE(stail);
452: continue; }
453: printf("smb_addcrc returned %d\n",j);
454: exit(1); }
455:
456: while(taillen && stail[taillen-1]<=SP) /* trim all garbage off the tail */
457: taillen--;
458:
459: net=NET_FIDO; /* Record origin address */
460: smb_hfield(&msg,SENDERNETTYPE,sizeof(ushort),&net);
461: smb_hfield(&msg,SENDERNETADDR,sizeof(fidoaddr_t),&origaddr);
462:
463: if(!orig) { /* No origin line means NetMail, so add dest addr */
464: smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(ushort),&net);
465: smb_hfield(&msg,RECIPIENTNETADDR,sizeof(fidoaddr_t),&destaddr); }
466:
467: if(smb_open_da(10)) {
468: printf("error opening %s.SDA\n",smb_file);
469: exit(1); }
470: l=bodylen+2;
471: if(taillen)
472: l+=(taillen+2);
473: msg.hdr.offset=smb_fallocdat(l,1);
474: fclose(sda_fp);
475: if(msg.hdr.offset && msg.hdr.offset<1L) {
476: printf("error %ld allocating records\r\n",msg.hdr.offset);
477: exit(1); }
478: fseek(sdt_fp,msg.hdr.offset,SEEK_SET);
479: xlat=XLAT_NONE;
480: fwrite(&xlat,2,1,sdt_fp);
481: l=ftell(sdt_fp);
482: fwrite(sbody,SDT_BLOCK_LEN,smb_datblocks(bodylen),sdt_fp);
483: if(taillen) {
484: fseek(sdt_fp,l+bodylen,SEEK_SET);
485: fwrite(&xlat,2,1,sdt_fp);
486: fwrite(stail,SDT_BLOCK_LEN,smb_datblocks(taillen),sdt_fp); }
487: fflush(sdt_fp);
488: FREE(fbuf);
489: FREE(sbody);
490: FREE(stail);
491:
492: smb_dfield(&msg,TEXT_BODY,bodylen+2);
493: if(taillen)
494: smb_dfield(&msg,TEXT_TAIL,taillen+2);
495:
496: smb_addmsghdr(&msg,&status,1,10);
497: smb_freemsgmem(msg); }
498:
499: printf("\n%u messages converted.\n",found);
500: return(0);
501: }
502:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.