|
|
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.