|
|
1.1 root 1: /* smbutil.c */
2:
3: /* Synchronet message base (SMB) utility */
4:
5: /* $Id: smbutil.c,v 1.93 2005/09/29 01:01:36 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #define SMBUTIL_VER "2.33"
39: char revision[16];
40: char compiler[32];
41:
42: const char *wday[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
43: const char *mon[]={"Jan","Feb","Mar","Apr","May","Jun"
44: ,"Jul","Aug","Sep","Oct","Nov","Dec"};
45:
46:
47: #define NOANALYSIS (1L<<0)
48: #define NOCRC (1L<<1)
49:
50: #ifdef __WATCOMC__
51: #define ffblk find_t
52: #define findfirst(x,y,z) _dos_findfirst(x,z,y)
53: #define findnext(x) _dos_findnext(x)
54: #endif
55:
56: #if defined(_WIN32)
57: #include <ctype.h> /* isdigit() */
58: #include <conio.h> /* getch() */
59: #endif
60:
61: /* ANSI */
62: #include <stdio.h>
63: #include <time.h> /* time */
64: #include <errno.h> /* errno */
65: #include <string.h> /* strrchr */
66: #include <ctype.h> /* toupper */
67:
68: #include "genwrap.h" /* stricmp */
69: #include "dirwrap.h" /* fexist */
70: #include "conwrap.h" /* getch */
71: #include "filewrap.h"
72: #include "smblib.h"
73: #include "crc16.h"
74: #include "crc32.h"
75: #include "gen_defs.h" /* MAX_PATH */
76:
77: #ifdef __WATCOMC__
78: #include <dos.h>
79: #endif
80:
81: /* gets is dangerous */
82: #define gets(str) fgets((str), sizeof(str), stdin)
83:
84: #define CHSIZE_FP(fp,size) if(chsize(fileno(fp),size)) printf("chsize failed!\n");
85:
86: /********************/
87: /* Global variables */
88: /********************/
89:
90: smb_t smb;
91: ulong mode=0L;
92: ushort tzone=0;
93: ushort xlat=XLAT_NONE;
94: FILE* nulfp;
95: FILE* errfp;
96: FILE* statfp;
97: BOOL pause_on_exit=FALSE;
98: BOOL pause_on_error=FALSE;
99: char* beep="";
100:
101: /************************/
102: /* Program usage/syntax */
103: /************************/
104:
105: char *usage=
106: "usage: smbutil [-opts] cmd <filespec.shd>\n"
107: "\n"
108: "cmd:\n"
109: " l[n] = list msgs starting at number n\n"
110: " r[n] = read msgs starting at number n\n"
111: " x[n] = dump msg index at number n\n"
112: " v[n] = view msg headers starting at number n\n"
113: " i[f] = import msg from text file f (or use stdin)\n"
114: " e[f] = import e-mail from text file f (or use stdin)\n"
115: " n[f] = import netmail from text file f (or use stdin)\n"
116: " h = dump hash file\n"
117: " s = display msg base status\n"
118: " c = change msg base status\n"
119: " d = delete all msgs\n"
120: " m = maintain msg base - delete old msgs and msgs over max\n"
121: " p[k] = pack msg base (k specifies minimum packable Kbytes)\n"
122: "opts:\n"
123: " c[m] = create message base if it doesn't exist (m=max msgs)\n"
124: " a = always pack msg base (disable compression analysis)\n"
125: " i = ignore dupes (do not store CRCs or search for duplicate hashes)\n"
126: " d = use default values (no prompt) for to, from, and subject\n"
127: " l = LZH-compress message text\n"
128: " o = print errors on stdout (instead of stderr)\n"
129: " p = wait for keypress (pause) on exit\n"
130: " ! = wait for keypress (pause) on error\n"
131: " b = beep on error\n"
132: " t<s> = set 'to' user name for imported message\n"
133: " n<s> = set 'to' netmail address for imported message\n"
134: " u<s> = set 'to' user number for imported message\n"
135: " f<s> = set 'from' user name for imported message\n"
136: " e<s> = set 'from' user number for imported message\n"
137: " s<s> = set 'subject' for imported message\n"
138: " z[n] = set time zone (n=min +/- from UT or 'EST','EDT','CST',etc)\n"
139: " # = set number of messages to view/list (e.g. -1)\n"
140: ;
141:
142: void bail(int code)
143: {
144:
145: if(pause_on_exit || (code && pause_on_error)) {
146: fprintf(statfp,"\nHit enter to continue...");
147: getchar();
148: }
149:
150: if(code)
151: fprintf(statfp,"\nReturning error code: %d\n",code);
152: exit(code);
153: }
154:
155: /*****************************************************************************/
156: /* Expands Unix LF to CRLF */
157: /*****************************************************************************/
158: ulong lf_expand(BYTE* inbuf, BYTE* outbuf)
159: {
160: ulong i,j;
161:
162: for(i=j=0;inbuf[i];i++) {
163: if(inbuf[i]=='\n' && (!i || inbuf[i-1]!='\r'))
164: outbuf[j++]='\r';
165: outbuf[j++]=inbuf[i];
166: }
167: outbuf[j]=0;
168: return(j);
169: }
170:
171: /****************************************************************************/
172: /* Adds a new message to the message base */
173: /****************************************************************************/
174: void postmsg(char type, char* to, char* to_number, char* to_address,
175: char* from, char* from_number, char* subject, FILE* fp)
176: {
177: char str[128];
178: char buf[1024];
179: char* msgtxt=NULL;
180: char* newtxt;
181: long msgtxtlen;
182: ushort net;
183: int i;
184: ushort agent=AGENT_SMBUTIL;
185: smbmsg_t msg;
186: long dupechk_hashes=SMB_HASH_SOURCE_ALL;
187:
188: /* Read message text from stream (file or stdin) */
189: msgtxtlen=0;
190: while(!feof(fp)) {
191: i=fread(buf,1,sizeof(buf),fp);
192: if(i<1)
193: break;
194: if((msgtxt=(char*)realloc(msgtxt,msgtxtlen+i+1))==NULL) {
195: fprintf(errfp,"\n%s!realloc(%ld) failure\n",beep,msgtxtlen+i+1);
196: bail(1);
197: }
198: memcpy(msgtxt+msgtxtlen,buf,i);
199: msgtxtlen+=i;
200: }
201:
202: if(msgtxt!=NULL) {
203:
204: msgtxt[msgtxtlen]=0; /* Must be NULL-terminated */
205:
206: if((newtxt=(char*)malloc((msgtxtlen*2)+1))==NULL) {
207: fprintf(errfp,"\n%s!malloc(%ld) failure\n",beep,(msgtxtlen*2)+1);
208: bail(1);
209: }
210:
211: /* Expand LFs to CRLFs */
212: msgtxtlen=lf_expand(msgtxt, newtxt);
213: free(msgtxt);
214: msgtxt=newtxt;
215: }
216:
217: memset(&msg,0,sizeof(smbmsg_t));
218: msg.hdr.when_written.time=time(NULL);
219: msg.hdr.when_written.zone=tzone;
220: msg.hdr.when_imported=msg.hdr.when_written;
221:
222: if((to==NULL || stricmp(to,"All")==0) && to_address!=NULL)
223: to=to_address;
224: if(to==NULL) {
225: printf("To User Name: ");
226: fgets(str,sizeof(str),stdin);
227: } else
228: SAFECOPY(str,to);
229: truncsp(str);
230:
231: if((i=smb_hfield_str(&msg,RECIPIENT,str))!=SMB_SUCCESS) {
232: fprintf(errfp,"\n%s!smb_hfield_str(0x%02X) returned %d: %s\n"
233: ,beep,RECIPIENT,i,smb.last_error);
234: bail(1);
235: }
236: if(type=='E' || type=='N')
237: smb.status.attr|=SMB_EMAIL;
238: if(smb.status.attr&SMB_EMAIL) {
239: if(to_address==NULL) {
240: if(to_number==NULL) {
241: printf("To User Number: ");
242: gets(str);
243: } else
244: SAFECOPY(str,to_number);
245: truncsp(str);
246: if((i=smb_hfield_str(&msg,RECIPIENTEXT,str))!=SMB_SUCCESS) {
247: fprintf(errfp,"\n%s!smb_hfield_str(0x%02X) returned %d: %s\n"
248: ,beep,RECIPIENTEXT,i,smb.last_error);
249: bail(1);
250: }
251: }
252: }
253:
254: if(smb.status.attr&SMB_EMAIL && (type=='N' || to_address!=NULL)) {
255: if(to_address==NULL) {
256: printf("To Address (e.g. user@host): ");
257: gets(str);
258: } else
259: SAFECOPY(str,to_address);
260: truncsp(str);
261: if(*str) {
262: net=smb_netaddr_type(str);
263: if((i=smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(net),&net))!=SMB_SUCCESS) {
264: fprintf(errfp,"\n%s!smb_hfield(0x%02X) returned %d: %s\n"
265: ,beep,RECIPIENTNETTYPE,i,smb.last_error);
266: bail(1);
267: }
268: if((i=smb_hfield_str(&msg,RECIPIENTNETADDR,str))!=SMB_SUCCESS) {
269: fprintf(errfp,"\n%s!smb_hfield_str(0x%02X) returned %d: %s\n"
270: ,beep,RECIPIENTNETADDR,i,smb.last_error);
271: bail(1);
272: }
273: }
274: }
275:
276: if(from==NULL) {
277: printf("From User Name: ");
278: gets(str);
279: } else
280: SAFECOPY(str,from);
281: truncsp(str);
282: if((i=smb_hfield_str(&msg,SENDER,str))!=SMB_SUCCESS) {
283: fprintf(errfp,"\n%s!smb_hfield_str(0x%02X) returned %d: %s\n"
284: ,beep,SENDER,i,smb.last_error);
285: bail(1);
286: }
287: if(smb.status.attr&SMB_EMAIL) {
288: if(from_number==NULL) {
289: printf("From User Number: ");
290: gets(str);
291: } else
292: SAFECOPY(str,from_number);
293: truncsp(str);
294: if((i=smb_hfield_str(&msg,SENDEREXT,str))!=SMB_SUCCESS) {
295: fprintf(errfp,"\n%s!smb_hfield_str(0x%02X) returned %d: %s\n"
296: ,beep,SENDEREXT,i,smb.last_error);
297: bail(1);
298: }
299: }
300: if((i=smb_hfield(&msg, SENDERAGENT, sizeof(agent), &agent))!=SMB_SUCCESS) {
301: fprintf(errfp,"\n%s!smb_hfield(0x%02X) returned %d: %s\n"
302: ,beep,SENDERAGENT,i,smb.last_error);
303: bail(1);
304: }
305:
306: if(subject==NULL) {
307: printf("Subject: ");
308: gets(str);
309: } else
310: SAFECOPY(str,subject);
311: truncsp(str);
312: if((i=smb_hfield_str(&msg,SUBJECT,str))!=SMB_SUCCESS) {
313: fprintf(errfp,"\n%s!smb_hfield_str(0x%02X) returned %d: %s\n"
314: ,beep,SUBJECT,i,smb.last_error);
315: bail(1);
316: }
317:
318: safe_snprintf(str,sizeof(str),"SMBUTIL %s-%s r%s %s %s"
319: ,SMBUTIL_VER
320: ,PLATFORM_DESC
321: ,revision
322: ,__DATE__
323: ,compiler
324: );
325: if((i=smb_hfield_str(&msg,FIDOPID,str))!=SMB_SUCCESS) {
326: fprintf(errfp,"\n%s!smb_hfield_str(0x%02X) returned %d: %s\n"
327: ,beep,FIDOPID,i,smb.last_error);
328: bail(1);
329: }
330:
331: if(mode&NOCRC || smb.status.max_crcs==0) /* no CRC checking means no body text dupe checking */
332: dupechk_hashes&=~(1<<SMB_HASH_SOURCE_BODY);
333:
334: if((i=smb_addmsg(&smb,&msg,smb.status.attr&SMB_HYPERALLOC
335: ,dupechk_hashes,xlat,msgtxt,NULL))!=SMB_SUCCESS) {
336: fprintf(errfp,"\n%s!smb_addmsg returned %d: %s\n"
337: ,beep,i,smb.last_error);
338: bail(1);
339: }
340: smb_freemsgmem(&msg);
341:
342: FREE_AND_NULL(msgtxt);
343: }
344:
345: /****************************************************************************/
346: /* Shows the message base header */
347: /****************************************************************************/
348: void showstatus(void)
349: {
350: int i;
351:
352: i=smb_locksmbhdr(&smb);
353: if(i) {
354: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
355: ,beep,i,smb.last_error);
356: return;
357: }
358: i=smb_getstatus(&smb);
359: smb_unlocksmbhdr(&smb);
360: if(i) {
361: fprintf(errfp,"\n%s!smb_getstatus returned %d: %s\n"
362: ,beep,i,smb.last_error);
363: return;
364: }
365: printf("last_msg =%lu\n"
366: "total_msgs =%lu\n"
367: "header_offset =%lu\n"
368: "max_crcs =%lu\n"
369: "max_msgs =%lu\n"
370: "max_age =%u\n"
371: "attr =%04Xh\n"
372: ,smb.status.last_msg
373: ,smb.status.total_msgs
374: ,smb.status.header_offset
375: ,smb.status.max_crcs
376: ,smb.status.max_msgs
377: ,smb.status.max_age
378: ,smb.status.attr
379: );
380: }
381:
382: /****************************************************************************/
383: /* Configure message base header */
384: /****************************************************************************/
385: void config(void)
386: {
387: char max_msgs[128],max_crcs[128],max_age[128],header_offset[128],attr[128];
388: int i;
389:
390: i=smb_locksmbhdr(&smb);
391: if(i) {
392: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
393: ,beep,i,smb.last_error);
394: return;
395: }
396: i=smb_getstatus(&smb);
397: smb_unlocksmbhdr(&smb);
398: if(i) {
399: fprintf(errfp,"\n%s!smb_getstatus returned %d: %s\n"
400: ,beep,i,smb.last_error);
401: return;
402: }
403: printf("Header offset =%-5lu New value (CR=No Change): "
404: ,smb.status.header_offset);
405: gets(header_offset);
406: printf("Max msgs =%-5lu New value (CR=No Change): "
407: ,smb.status.max_msgs);
408: gets(max_msgs);
409: printf("Max crcs =%-5lu New value (CR=No Change): "
410: ,smb.status.max_crcs);
411: gets(max_crcs);
412: printf("Max age =%-5u New value (CR=No Change): "
413: ,smb.status.max_age);
414: gets(max_age);
415: printf("Attributes =%-5u New value (CR=No Change): "
416: ,smb.status.attr);
417: gets(attr);
418: i=smb_locksmbhdr(&smb);
419: if(i) {
420: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
421: ,beep,i,smb.last_error);
422: return;
423: }
424: i=smb_getstatus(&smb);
425: if(i) {
426: fprintf(errfp,"\n%s!smb_getstatus returned %d: %s\n"
427: ,beep,i,smb.last_error);
428: smb_unlocksmbhdr(&smb);
429: return;
430: }
431: if(isdigit(max_msgs[0]))
432: smb.status.max_msgs=atol(max_msgs);
433: if(isdigit(max_crcs[0]))
434: smb.status.max_crcs=atol(max_crcs);
435: if(isdigit(max_age[0]))
436: smb.status.max_age=atoi(max_age);
437: if(isdigit(header_offset[0]))
438: smb.status.header_offset=atol(header_offset);
439: if(isdigit(attr[0]))
440: smb.status.attr=atoi(attr);
441: i=smb_putstatus(&smb);
442: smb_unlocksmbhdr(&smb);
443: if(i)
444: fprintf(errfp,"\n%s!smb_putstatus returned %d: %s\n"
445: ,beep,i,smb.last_error);
446: }
447:
448: /****************************************************************************/
449: /* Lists messages' to, from, and subject */
450: /****************************************************************************/
451: void listmsgs(ulong start, ulong count)
452: {
453: int i;
454: ulong l=0;
455: smbmsg_t msg;
456:
457: if(!start)
458: start=1;
459: if(!count)
460: count=~0;
461: fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
462: while(l<count) {
463: if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
464: break;
465: i=smb_lockmsghdr(&smb,&msg);
466: if(i) {
467: fprintf(errfp,"\n%s!smb_lockmsghdr returned %d: %s\n"
468: ,beep,i,smb.last_error);
469: break;
470: }
471: i=smb_getmsghdr(&smb,&msg);
472: smb_unlockmsghdr(&smb,&msg);
473: if(i) {
474: fprintf(errfp,"\n%s!smb_getmsghdr returned %d: %s\n"
475: ,beep,i,smb.last_error);
476: break;
477: }
478: printf("%4lu %-25.25s %-25.25s %.20s\n"
479: ,msg.hdr.number,msg.from,msg.to,msg.subj);
480: smb_freemsgmem(&msg);
481: l++;
482: }
483: }
484:
485: char *binstr(uchar *buf, ushort length)
486: {
487: static char str[512];
488: char tmp[128];
489: int i;
490:
491: str[0]=0;
492: for(i=0;i<length;i++)
493: if(buf[i] && (buf[i]<' ' || buf[i]>=0x7f)
494: && buf[i]!='\r' && buf[i]!='\n' && buf[i]!='\t')
495: break;
496: if(i==length) /* not binary */
497: return((char*)buf);
498: for(i=0;i<length;i++) {
499: sprintf(tmp,"%02X ",buf[i]);
500: strcat(str,tmp);
501: if(i>=100) {
502: strcat(str,"...");
503: break;
504: }
505: }
506: return(str);
507: }
508:
509: /****************************************************************************/
510: /* Generates a 24 character ASCII string that represents the time_t pointer */
511: /* Used as a replacement for ctime() */
512: /****************************************************************************/
513: char *my_timestr(time_t *intime)
514: {
515: static char str[256];
516: char mer[3],hour;
517: struct tm *gm;
518:
519: gm=localtime(intime);
520: if(gm==NULL) {
521: strcpy(str,"Invalid Time");
522: return(str);
523: }
524: if(gm->tm_hour>=12) {
525: if(gm->tm_hour==12)
526: hour=12;
527: else
528: hour=gm->tm_hour-12;
529: strcpy(mer,"pm");
530: }
531: else {
532: if(gm->tm_hour==0)
533: hour=12;
534: else
535: hour=gm->tm_hour;
536: strcpy(mer,"am");
537: }
538: sprintf(str,"%s %s %02d %4d %02d:%02d %s"
539: ,wday[gm->tm_wday],mon[gm->tm_mon],gm->tm_mday,1900+gm->tm_year
540: ,hour,gm->tm_min,mer);
541: return(str);
542: }
543:
544: /****************************************************************************/
545: /****************************************************************************/
546: void dumpindex(ulong start, ulong count)
547: {
548: ulong l=0;
549: idxrec_t idx;
550:
551: if(!start)
552: start=1;
553: if(!count)
554: count=~0;
555: fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
556: while(l<count) {
557: if(!fread(&idx,1,sizeof(idx),smb.sid_fp))
558: break;
559:
560: printf("%4lu %04hX %04hX %04Xh %04Xh %06X %s\n"
561: ,idx.number,idx.from,idx.to,idx.subj,idx.attr
562: ,idx.offset,my_timestr((time_t*)&idx.time));
563: l++;
564: }
565: }
566:
567: /****************************************************************************/
568: /* Displays message header information */
569: /****************************************************************************/
570: void viewmsgs(ulong start, ulong count)
571: {
572: int i;
573: ulong l=0;
574: smbmsg_t msg;
575:
576: if(!start)
577: start=1;
578: if(!count)
579: count=~0;
580: fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
581: while(l<count) {
582: if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
583: break;
584: i=smb_lockmsghdr(&smb,&msg);
585: if(i) {
586: fprintf(errfp,"\n%s!smb_lockmsghdr returned %d: %s\n"
587: ,beep,i,smb.last_error);
588: break;
589: }
590: i=smb_getmsghdr(&smb,&msg);
591: smb_unlockmsghdr(&smb,&msg);
592: if(i) {
593: fprintf(errfp,"\n%s!smb_getmsghdr returned %d: %s\n"
594: ,beep,i,smb.last_error);
595: break;
596: }
597:
598: printf("--------------------\n");
599: printf("%-20.20s %ld\n" ,"index record",ftell(smb.sid_fp)/sizeof(idxrec_t));
600: smb_dump_msghdr(stdout,&msg);
601: printf("\n");
602: smb_freemsgmem(&msg);
603: l++;
604: }
605: }
606:
607: /****************************************************************************/
608: /****************************************************************************/
609: void dump_hashes(void)
610: {
611: char tmp[128];
612: int retval;
613: hash_t hash;
614:
615: if((retval=smb_open_hash(&smb))!=SMB_SUCCESS) {
616: fprintf(errfp,"\n%s!smb_open_hash returned %d: %s\n"
617: ,beep, retval, smb.last_error);
618: return;
619: }
620:
621: while(!smb_feof(smb.hash_fp)) {
622: if(smb_fread(&smb,&hash,sizeof(hash),smb.hash_fp)!=sizeof(hash))
623: break;
624: printf("\n");
625: printf("%-10s: %lu\n", "Number", hash.number);
626: printf("%-10s: %s\n", "Source", smb_hashsourcetype(hash.source));
627: printf("%-10s: %lu\n", "Length", hash.length);
628: printf("%-10s: %s\n", "Time", my_timestr((time_t*)&hash.time));
629: printf("%-10s: %x\n", "Flags", hash.flags);
630: if(hash.flags&SMB_HASH_CRC16)
631: printf("%-10s: %04x\n", "CRC-16", hash.crc16);
632: if(hash.flags&SMB_HASH_CRC32)
633: printf("%-10s: %08lx\n","CRC-32", hash.crc32);
634: if(hash.flags&SMB_HASH_MD5)
635: printf("%-10s: %s\n", "MD5", MD5_hex(tmp,hash.md5));
636: }
637:
638: smb_close_hash(&smb);
639: }
640:
641: /****************************************************************************/
642: /* Maintain message base - deletes messages older than max age (in days) */
643: /* or messages that exceed maximum */
644: /****************************************************************************/
645: void maint(void)
646: {
647: int i;
648: ulong l,m,n,f,flagged=0;
649: time_t now;
650: smbmsg_t msg;
651: idxrec_t *idx;
652:
653: printf("Maintaining %s\r\n",smb.file);
654: now=time(NULL);
655: i=smb_locksmbhdr(&smb);
656: if(i) {
657: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
658: ,beep,i,smb.last_error);
659: return;
660: }
661: i=smb_getstatus(&smb);
662: if(i) {
663: smb_unlocksmbhdr(&smb);
664: fprintf(errfp,"\n%s!smb_getstatus returned %d: %s\n"
665: ,beep,i,smb.last_error);
666: return;
667: }
668: if(!smb.status.total_msgs) {
669: smb_unlocksmbhdr(&smb);
670: printf("Empty\n");
671: return;
672: }
673: printf("Loading index...\n");
674: if((idx=(idxrec_t *)malloc(sizeof(idxrec_t)*smb.status.total_msgs))
675: ==NULL) {
676: smb_unlocksmbhdr(&smb);
677: fprintf(errfp,"\n%s!Error allocating %lu bytes of memory\n"
678: ,beep,sizeof(idxrec_t)*smb.status.total_msgs);
679: return;
680: }
681: fseek(smb.sid_fp,0L,SEEK_SET);
682: for(l=0;l<smb.status.total_msgs;l++) {
683: printf("%lu of %lu\r"
684: ,l+1,smb.status.total_msgs);
685: if(!fread(&idx[l],1,sizeof(idxrec_t),smb.sid_fp))
686: break;
687: }
688: printf("\nDone.\n\n");
689:
690: printf("Scanning for pre-flagged messages...\n");
691: for(m=0;m<l;m++) {
692: printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
693: if(idx[m].attr&MSG_DELETE)
694: flagged++;
695: }
696: printf("\r100%% (%lu pre-flagged for deletion)\n",flagged);
697:
698: if(smb.status.max_age) {
699: printf("Scanning for messages more than %u days old...\n"
700: ,smb.status.max_age);
701: for(m=f=0;m<l;m++) {
702: printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
703: if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
704: continue;
705: if((ulong)now>idx[m].time && (now-idx[m].time)/(24L*60L*60L)
706: >smb.status.max_age) {
707: f++;
708: flagged++;
709: idx[m].attr|=MSG_DELETE;
710: }
711: } /* mark for deletion */
712: printf("\r100%% (%lu flagged for deletion)\n",f);
713: }
714:
715: printf("Scanning for read messages to be killed...\n");
716: for(m=f=0;m<l;m++) {
717: printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
718: if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
719: continue;
720: if((idx[m].attr&(MSG_READ|MSG_KILLREAD))==(MSG_READ|MSG_KILLREAD)) {
721: f++;
722: flagged++;
723: idx[m].attr|=MSG_DELETE;
724: }
725: }
726: printf("\r100%% (%lu flagged for deletion)\n",f);
727:
728: if(smb.status.max_msgs && l-flagged>smb.status.max_msgs) {
729: printf("Flagging excess messages for deletion...\n");
730: for(m=n=0,f=flagged;l-flagged>smb.status.max_msgs && m<l;m++) {
731: if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
732: continue;
733: printf("%lu of %lu\r",++n,(l-f)-smb.status.max_msgs);
734: flagged++;
735: idx[m].attr|=MSG_DELETE;
736: } /* mark for deletion */
737: printf("\nDone.\n\n");
738: }
739:
740: if(!flagged) { /* No messages to delete */
741: free(idx);
742: smb_unlocksmbhdr(&smb);
743: return;
744: }
745:
746: if(!(mode&NOANALYSIS)) {
747:
748: printf("Freeing allocated header and data blocks for deleted messages...\n");
749: if(!(smb.status.attr&SMB_HYPERALLOC)) {
750: i=smb_open_da(&smb);
751: if(i) {
752: smb_unlocksmbhdr(&smb);
753: fprintf(errfp,"\n%s!smb_open_da returned %d: %s\n"
754: ,beep,i,smb.last_error);
755: bail(1);
756: }
757: i=smb_open_ha(&smb);
758: if(i) {
759: smb_unlocksmbhdr(&smb);
760: fprintf(errfp,"\n%s!smb_open_ha returned %d: %s\n"
761: ,beep,i,smb.last_error);
762: bail(1);
763: }
764: }
765:
766: for(m=n=0;m<l;m++) {
767: if(idx[m].attr&MSG_DELETE) {
768: printf("%lu of %lu\r",++n,flagged);
769: msg.idx=idx[m];
770: msg.hdr.number=msg.idx.number;
771: if((i=smb_getmsgidx(&smb,&msg))!=0) {
772: fprintf(errfp,"\n%s!smb_getmsgidx returned %d: %s\n"
773: ,beep,i,smb.last_error);
774: continue;
775: }
776: i=smb_lockmsghdr(&smb,&msg);
777: if(i) {
778: fprintf(errfp,"\n%s!smb_lockmsghdr returned %d: %s\n"
779: ,beep,i,smb.last_error);
780: break;
781: }
782: if((i=smb_getmsghdr(&smb,&msg))!=0) {
783: smb_unlockmsghdr(&smb,&msg);
784: fprintf(errfp,"\n%s!smb_getmsghdr returned %d: %s\n"
785: ,beep,i,smb.last_error);
786: break;
787: }
788: msg.hdr.attr|=MSG_DELETE; /* mark header as deleted */
789: if((i=smb_putmsg(&smb,&msg))!=0) {
790: smb_freemsgmem(&msg);
791: smb_unlockmsghdr(&smb,&msg);
792: fprintf(errfp,"\n%s!smb_putmsg returned %d: %s\n"
793: ,beep,i,smb.last_error);
794: break;
795: }
796: smb_unlockmsghdr(&smb,&msg);
797: if((i=smb_freemsg(&smb,&msg))!=0) {
798: smb_freemsgmem(&msg);
799: fprintf(errfp,"\n%s!smb_freemsg returned %d: %s\n"
800: ,beep,i,smb.last_error);
801: break;
802: }
803: smb_freemsgmem(&msg);
804: }
805: }
806: if(!(smb.status.attr&SMB_HYPERALLOC)) {
807: smb_close_ha(&smb);
808: smb_close_da(&smb);
809: }
810: printf("\nDone.\n\n");
811: }
812:
813: printf("Re-writing index...\n");
814: rewind(smb.sid_fp);
815: CHSIZE_FP(smb.sid_fp,0);
816: for(m=n=0;m<l;m++) {
817: if(idx[m].attr&MSG_DELETE)
818: continue;
819: printf("%lu of %lu\r",++n,l-flagged);
820: fwrite(&idx[m],sizeof(idxrec_t),1,smb.sid_fp);
821: }
822: printf("\nDone.\n\n");
823: fflush(smb.sid_fp);
824:
825: free(idx);
826: smb.status.total_msgs-=flagged;
827: smb_putstatus(&smb);
828: smb_unlocksmbhdr(&smb);
829: }
830:
831:
832: typedef struct {
833: ulong old,new;
834: } datoffset_t;
835:
836: /****************************************************************************/
837: /* Removes all unused blocks from SDT and SHD files */
838: /****************************************************************************/
839: void packmsgs(ulong packable)
840: {
841: uchar str[128],buf[SDT_BLOCK_LEN],ch,fname[128],tmpfname[128];
842: int i,size;
843: ulong l,m,n,datoffsets=0,length,total,now;
844: FILE *tmp_sdt,*tmp_shd,*tmp_sid;
845: BOOL error=FALSE;
846: smbhdr_t hdr;
847: smbmsg_t msg;
848: datoffset_t *datoffset=NULL;
849:
850: now=time(NULL);
851: printf("Packing %s\n",smb.file);
852: i=smb_locksmbhdr(&smb);
853: if(i) {
854: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
855: ,beep,i,smb.last_error);
856: return;
857: }
858: i=smb_getstatus(&smb);
859: if(i) {
860: smb_unlocksmbhdr(&smb);
861: fprintf(errfp,"\n%s!smb_getstatus returned %d: %s\n"
862: ,beep,i,smb.last_error);
863: return;
864: }
865:
866: if(!(smb.status.attr&SMB_HYPERALLOC)) {
867: i=smb_open_ha(&smb);
868: if(i) {
869: smb_unlocksmbhdr(&smb);
870: fprintf(errfp,"\n%s!smb_open_ha returned %d: %s\n"
871: ,beep,i,smb.last_error);
872: return;
873: }
874: i=smb_open_da(&smb);
875: if(i) {
876: smb_unlocksmbhdr(&smb);
877: smb_close_ha(&smb);
878: fprintf(errfp,"\n%s!smb_open_da returned %d: %s\n"
879: ,beep,i,smb.last_error);
880: return;
881: }
882: }
883:
884: if(!smb.status.total_msgs) {
885: printf("Empty\n");
886: rewind(smb.shd_fp);
887: CHSIZE_FP(smb.shd_fp,smb.status.header_offset);
888: rewind(smb.sdt_fp);
889: CHSIZE_FP(smb.sdt_fp,0);
890: rewind(smb.sid_fp);
891: CHSIZE_FP(smb.sid_fp,0);
892: if(!(smb.status.attr&SMB_HYPERALLOC)) {
893: rewind(smb.sha_fp);
894: CHSIZE_FP(smb.sha_fp,0);
895: rewind(smb.sda_fp);
896: CHSIZE_FP(smb.sda_fp,0);
897: smb_close_ha(&smb);
898: smb_close_da(&smb);
899: }
900: smb_unlocksmbhdr(&smb);
901: return;
902: }
903:
904:
905: if(!(smb.status.attr&SMB_HYPERALLOC) && !(mode&NOANALYSIS)) {
906: printf("Analyzing data blocks...\n");
907:
908: length=filelength(fileno(smb.sda_fp));
909:
910: fseek(smb.sda_fp,0L,SEEK_SET);
911: for(l=m=0;l<length;l+=2) {
912: printf("\r%2lu%% ",l ? (long)(100.0/((float)length/l)) : 0);
913: i=0;
914: if(!fread(&i,2,1,smb.sda_fp))
915: break;
916: if(!i)
917: m++;
918: }
919:
920: printf("\rAnalyzing header blocks...\n");
921:
922: length=filelength(fileno(smb.sha_fp));
923:
924: fseek(smb.sha_fp,0L,SEEK_SET);
925: for(l=n=0;l<length;l++) {
926: printf("\r%2lu%% ",l ? (long)(100.0/((float)length/l)) : 0);
927: ch=0;
928: if(!fread(&ch,1,1,smb.sha_fp))
929: break;
930: if(!ch)
931: n++;
932: }
933:
934: if(!m && !n) {
935: printf("\rAlready compressed.\n\n");
936: smb_close_ha(&smb);
937: smb_close_da(&smb);
938: smb_unlocksmbhdr(&smb);
939: return;
940: }
941:
942: if(packable && (m*SDT_BLOCK_LEN)+(n*SHD_BLOCK_LEN)<packable*1024L) {
943: printf("\rLess than %luk compressible bytes.\n\n",packable);
944: smb_close_ha(&smb);
945: smb_close_da(&smb);
946: smb_unlocksmbhdr(&smb);
947: return;
948: }
949:
950: printf("\rCompressing %lu data blocks (%lu bytes)\n"
951: " and %lu header blocks (%lu bytes)\n"
952: ,m,m*SDT_BLOCK_LEN,n,n*SHD_BLOCK_LEN);
953: }
954:
955: if(!(smb.status.attr&SMB_HYPERALLOC)) {
956: rewind(smb.sha_fp);
957: CHSIZE_FP(smb.sha_fp,0); /* Reset both allocation tables */
958: rewind(smb.sda_fp);
959: CHSIZE_FP(smb.sda_fp,0);
960: }
961:
962: if(smb.status.attr&SMB_HYPERALLOC && !(mode&NOANALYSIS)) {
963: printf("Analyzing %s\n",smb.file);
964:
965: length=filelength(fileno(smb.shd_fp));
966: m=n=0;
967: for(l=smb.status.header_offset;l<length;l+=size) {
968: printf("\r%2lu%% ",(long)(100.0/((float)length/l)));
969: msg.idx.offset=l;
970: if((i=smb_lockmsghdr(&smb,&msg))!=0) {
971: printf("\n(%06lX) smb_lockmsghdr returned %d\n",l,i);
972: size=SHD_BLOCK_LEN;
973: continue;
974: }
975: if((i=smb_getmsghdr(&smb,&msg))!=0) {
976: smb_unlockmsghdr(&smb,&msg);
977: m++;
978: size=SHD_BLOCK_LEN;
979: continue;
980: }
981: smb_unlockmsghdr(&smb,&msg);
982: if(msg.hdr.attr&MSG_DELETE) {
983: m+=smb_hdrblocks(msg.hdr.length);
984: n+=smb_datblocks(smb_getmsgdatlen(&msg));
985: }
986: size=smb_hdrblocks(smb_getmsghdrlen(&msg))*SHD_BLOCK_LEN;
987: smb_freemsgmem(&msg);
988: }
989:
990:
991: if(!m && !n) {
992: printf("\rAlready compressed.\n\n");
993: smb_unlocksmbhdr(&smb);
994: return;
995: }
996:
997: if(packable && (n*SDT_BLOCK_LEN)+(m*SHD_BLOCK_LEN)<packable*1024L) {
998: printf("\rLess than %luk compressible bytes.\n\n",packable);
999: smb_unlocksmbhdr(&smb);
1000: return;
1001: }
1002:
1003: printf("\rCompressing %lu data blocks (%lu bytes)\n"
1004: " and %lu header blocks (%lu bytes)\n"
1005: ,n,n*SDT_BLOCK_LEN,m,m*SHD_BLOCK_LEN);
1006: }
1007:
1008: sprintf(fname,"%s.sd$",smb.file);
1009: tmp_sdt=fopen(fname,"wb");
1010: sprintf(fname,"%s.sh$",smb.file);
1011: tmp_shd=fopen(fname,"wb");
1012: sprintf(fname,"%s.si$",smb.file);
1013: tmp_sid=fopen(fname,"wb");
1014: if(!tmp_sdt || !tmp_shd || !tmp_sid) {
1015: smb_unlocksmbhdr(&smb);
1016: if(!(smb.status.attr&SMB_HYPERALLOC)) {
1017: smb_close_ha(&smb);
1018: smb_close_da(&smb);
1019: }
1020: fprintf(errfp,"\n%s!Error opening temp files\n",beep);
1021: return;
1022: }
1023: setvbuf(tmp_sdt,NULL,_IOFBF,2*1024);
1024: setvbuf(tmp_shd,NULL,_IOFBF,2*1024);
1025: setvbuf(tmp_sid,NULL,_IOFBF,2*1024);
1026: if(!(smb.status.attr&SMB_HYPERALLOC)
1027: && (datoffset=(datoffset_t *)malloc(sizeof(datoffset_t)*smb.status.total_msgs))
1028: ==NULL) {
1029: smb_unlocksmbhdr(&smb);
1030: smb_close_ha(&smb);
1031: smb_close_da(&smb);
1032: fclose(tmp_sdt);
1033: fclose(tmp_shd);
1034: fclose(tmp_sid);
1035: fprintf(errfp,"\n%s!Error allocating memory\n",beep);
1036: return;
1037: }
1038: fseek(smb.shd_fp,0L,SEEK_SET);
1039: fread(&hdr,1,sizeof(smbhdr_t),smb.shd_fp);
1040: fwrite(&hdr,1,sizeof(smbhdr_t),tmp_shd);
1041: fwrite(&(smb.status),1,sizeof(smbstatus_t),tmp_shd);
1042: for(l=sizeof(smbhdr_t)+sizeof(smbstatus_t);l<smb.status.header_offset;l++) {
1043: fread(&ch,1,1,smb.shd_fp); /* copy additional base header records */
1044: fwrite(&ch,1,1,tmp_shd);
1045: }
1046: fseek(smb.sid_fp,0L,SEEK_SET);
1047: total=0;
1048: for(l=0;l<smb.status.total_msgs;l++) {
1049: printf("%lu of %lu\r",l+1,smb.status.total_msgs);
1050: if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
1051: break;
1052: if(msg.idx.attr&MSG_DELETE) {
1053: printf("\nDeleted index.\n");
1054: continue;
1055: }
1056: i=smb_lockmsghdr(&smb,&msg);
1057: if(i) {
1058: fprintf(errfp,"\n%s!smb_lockmsghdr returned %d: %s\n"
1059: ,beep,i,smb.last_error);
1060: continue;
1061: }
1062: i=smb_getmsghdr(&smb,&msg);
1063: smb_unlockmsghdr(&smb,&msg);
1064: if(i) {
1065: fprintf(errfp,"\n%s!smb_getmsghdr returned %d: %s\n"
1066: ,beep,i,smb.last_error);
1067: continue;
1068: }
1069: if(msg.hdr.attr&MSG_DELETE) {
1070: printf("\nDeleted header.\n");
1071: smb_freemsgmem(&msg);
1072: continue;
1073: }
1074: if(msg.expiration && msg.expiration<=now) {
1075: printf("\nExpired message.\n");
1076: smb_freemsgmem(&msg);
1077: continue;
1078: }
1079: for(m=0;m<datoffsets;m++)
1080: if(msg.hdr.offset==datoffset[m].old)
1081: break;
1082: if(m<datoffsets) { /* another index pointed to this data */
1083: printf("duplicate index\n");
1084: msg.hdr.offset=datoffset[m].new;
1085: smb_incmsgdat(&smb,datoffset[m].new,smb_getmsgdatlen(&msg),1);
1086: } else {
1087:
1088: if(!(smb.status.attr&SMB_HYPERALLOC))
1089: datoffset[datoffsets].old=msg.hdr.offset;
1090:
1091: fseek(smb.sdt_fp,msg.hdr.offset,SEEK_SET);
1092:
1093: m=smb_getmsgdatlen(&msg);
1094: if(m>16L*1024L*1024L) {
1095: fprintf(errfp,"\n%s!Invalid data length (%lu)\n",beep,m);
1096: continue;
1097: }
1098:
1099: if(!(smb.status.attr&SMB_HYPERALLOC)) {
1100: datoffset[datoffsets].new=msg.hdr.offset
1101: =smb_fallocdat(&smb,m,1);
1102: datoffsets++;
1103: fseek(tmp_sdt,msg.hdr.offset,SEEK_SET);
1104: }
1105: else {
1106: fseek(tmp_sdt,0L,SEEK_END);
1107: msg.hdr.offset=ftell(tmp_sdt);
1108: }
1109:
1110: /* Actually copy the data */
1111:
1112: n=smb_datblocks(m);
1113: for(m=0;m<n;m++) {
1114: fread(buf,1,SDT_BLOCK_LEN,smb.sdt_fp);
1115: if(!m && *(ushort *)buf!=XLAT_NONE && *(ushort *)buf!=XLAT_LZH) {
1116: printf("\nUnsupported translation type (%04X)\n"
1117: ,*(ushort *)buf);
1118: break;
1119: }
1120: fwrite(buf,1,SDT_BLOCK_LEN,tmp_sdt);
1121: }
1122: if(m<n)
1123: continue;
1124: }
1125:
1126: /* Write the new index entry */
1127: length=smb_getmsghdrlen(&msg);
1128: if(smb.status.attr&SMB_HYPERALLOC)
1129: msg.idx.offset=ftell(tmp_shd);
1130: else
1131: msg.idx.offset=smb_fallochdr(&smb,length)+smb.status.header_offset;
1132: msg.idx.number=msg.hdr.number;
1133: msg.idx.attr=msg.hdr.attr;
1134: msg.idx.time=msg.hdr.when_imported.time;
1135: msg.idx.subj=smb_subject_crc(msg.subj);
1136: if(smb.status.attr&SMB_EMAIL) {
1137: if(msg.to_ext)
1138: msg.idx.to=atoi(msg.to_ext);
1139: else
1140: msg.idx.to=0;
1141: if(msg.from_ext)
1142: msg.idx.from=atoi(msg.from_ext);
1143: else
1144: msg.idx.from=0;
1145: }
1146: else {
1147: SAFECOPY(str,msg.to);
1148: strlwr(str);
1149: msg.idx.to=crc16(str,0);
1150: SAFECOPY(str,msg.from);
1151: strlwr(str);
1152: msg.idx.from=crc16(str,0);
1153: }
1154: fwrite(&msg.idx,1,sizeof(idxrec_t),tmp_sid);
1155:
1156: /* Write the new header entry */
1157: fseek(tmp_shd,msg.idx.offset,SEEK_SET);
1158: fwrite(&msg.hdr,1,sizeof(msghdr_t),tmp_shd);
1159: for(n=0;n<msg.hdr.total_dfields;n++)
1160: fwrite(&msg.dfield[n],1,sizeof(dfield_t),tmp_shd);
1161: for(n=0;n<msg.total_hfields;n++) {
1162: fwrite(&msg.hfield[n],1,sizeof(hfield_t),tmp_shd);
1163: fwrite(msg.hfield_dat[n],1,msg.hfield[n].length,tmp_shd);
1164: }
1165: while(length%SHD_BLOCK_LEN) { /* pad with NULLs */
1166: fputc(0,tmp_shd);
1167: length++;
1168: }
1169: total++;
1170: smb_freemsgmem(&msg);
1171: }
1172:
1173: if(datoffset)
1174: free(datoffset);
1175: if(!(smb.status.attr&SMB_HYPERALLOC)) {
1176: smb_close_ha(&smb);
1177: smb_close_da(&smb);
1178: }
1179:
1180: /* Change *.sh$ into *.shd */
1181: fclose(smb.shd_fp), smb.shd_fp=NULL;
1182: fclose(tmp_shd);
1183: sprintf(fname,"%s.shd",smb.file);
1184: if(remove(fname)!=0) {
1185: error=TRUE;
1186: fprintf(errfp,"\n%s!Error %d removing %s\n",beep,errno,fname);
1187: }
1188: sprintf(tmpfname,"%s.sh$",smb.file);
1189: if(!error && rename(tmpfname,fname)!=0) {
1190: error=TRUE;
1191: fprintf(errfp,"\n%s!Error %d renaming %s to %s\n",beep,errno,tmpfname,fname);
1192: }
1193:
1194:
1195: /* Change *.sd$ into *.sdt */
1196: fclose(smb.sdt_fp), smb.sdt_fp=NULL;
1197: fclose(tmp_sdt);
1198: sprintf(fname,"%s.sdt",smb.file);
1199: if(!error && remove(fname)!=0) {
1200: error=TRUE;
1201: fprintf(errfp,"\n%s!Error %d removing %s\n",beep,errno,fname);
1202: }
1203:
1204: sprintf(tmpfname,"%s.sd$",smb.file);
1205: if(!error && rename(tmpfname,fname)!=0) {
1206: error=TRUE;
1207: fprintf(errfp,"\n%s!Error %d renaming %s to %s\n",beep,errno,tmpfname,fname);
1208: }
1209:
1210: /* Change *.si$ into *.sid */
1211: fclose(smb.sid_fp), smb.sid_fp=NULL;
1212: fclose(tmp_sid);
1213: sprintf(fname,"%s.sid",smb.file);
1214: if(!error && remove(fname)!=0) {
1215: error=TRUE;
1216: fprintf(errfp,"\n%s!Error %d removing %s\n",beep,errno,fname);
1217: }
1218:
1219: sprintf(tmpfname,"%s.si$",smb.file);
1220: if(!error && rename(tmpfname,fname)!=0) {
1221: error=TRUE;
1222: fprintf(errfp,"\n%s!Error %d renaming %s to %s\n",beep,errno,tmpfname,fname);
1223: }
1224:
1225: if((i=smb_unlock(&smb))!=0)
1226: fprintf(errfp,"\n%s!ERROR %d (%s) unlocking %s\n"
1227: ,beep,i,smb.last_error,smb.file);
1228:
1229: if((i=smb_open(&smb))!=0) {
1230: fprintf(errfp,"\n%s!Error %d (%s) reopening %s\n"
1231: ,beep,i,smb.last_error,smb.file);
1232: return;
1233: }
1234: if((i=smb_locksmbhdr(&smb))!=0)
1235: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
1236: ,beep,i,smb.last_error);
1237: smb.status.total_msgs=total;
1238: if((i=smb_putstatus(&smb))!=0)
1239: fprintf(errfp,"\n%s!smb_putstatus returned %d: %s\n"
1240: ,beep,i,smb.last_error);
1241: smb_unlocksmbhdr(&smb);
1242: printf("\nDone.\n\n");
1243: }
1244:
1245: void delmsgs(void)
1246: {
1247: int i;
1248:
1249: printf("Deleting %s\n",smb.file);
1250:
1251: i=smb_locksmbhdr(&smb);
1252: if(i) {
1253: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
1254: ,beep,i,smb.last_error);
1255: return;
1256: }
1257: i=smb_getstatus(&smb);
1258: if(i) {
1259: smb_unlocksmbhdr(&smb);
1260: fprintf(errfp,"\n%s!smb_getstatus returned %d: %s\n"
1261: ,beep,i,smb.last_error);
1262: return;
1263: }
1264: if(!(smb.status.attr&SMB_HYPERALLOC)) {
1265: i=smb_open_da(&smb);
1266: if(i) {
1267: smb_unlocksmbhdr(&smb);
1268: fprintf(errfp,"\n%s!smb_open_da returned %d: %s\n"
1269: ,beep,i,smb.last_error);
1270: bail(1);
1271: }
1272: i=smb_open_ha(&smb);
1273: if(i) {
1274: smb_unlocksmbhdr(&smb);
1275: fprintf(errfp,"\n%s!smb_open_ha returned %d: %s\n"
1276: ,beep,i,smb.last_error);
1277: bail(1);
1278: }
1279: /* Reset both allocation tables */
1280: CHSIZE_FP(smb.sha_fp,0);
1281: CHSIZE_FP(smb.sda_fp,0);
1282: smb_close_ha(&smb);
1283: smb_close_da(&smb);
1284: }
1285:
1286: CHSIZE_FP(smb.sid_fp,0);
1287: CHSIZE_FP(smb.shd_fp,smb.status.header_offset);
1288: CHSIZE_FP(smb.sdt_fp,0);
1289:
1290: /* re-write status header */
1291: smb.status.total_msgs=0;
1292: if((i=smb_putstatus(&smb))!=0)
1293: fprintf(errfp,"\n%s!smb_putstatus returned %d: %s\n"
1294: ,beep,i,smb.last_error);
1295: smb_unlocksmbhdr(&smb);
1296: printf("\nDone.\n\n");
1297: }
1298:
1299: /****************************************************************************/
1300: /* Read messages in message base */
1301: /****************************************************************************/
1302: void readmsgs(ulong start)
1303: {
1304: char *inbuf;
1305: int i,done=0,domsg=1;
1306: smbmsg_t msg;
1307:
1308: if(start)
1309: msg.offset=start-1;
1310: else
1311: msg.offset=0;
1312: while(!done) {
1313: if(domsg) {
1314: fseek(smb.sid_fp,msg.offset*sizeof(idxrec_t),SEEK_SET);
1315: if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
1316: break;
1317: i=smb_lockmsghdr(&smb,&msg);
1318: if(i) {
1319: fprintf(errfp,"\n%s!smb_lockmsghdr returned %d: %s\n"
1320: ,beep,i,smb.last_error);
1321: break;
1322: }
1323: i=smb_getmsghdr(&smb,&msg);
1324: if(i) {
1325: fprintf(errfp,"\n%s!smb_getmsghdr returned %d: %s\n"
1326: ,beep,i,smb.last_error);
1327: break;
1328: }
1329:
1330: printf("\n%lu (%lu)\n",msg.hdr.number,msg.offset+1);
1331: printf("Subj : %s\n",msg.subj);
1332: printf("To : %s",msg.to);
1333: if(msg.to_net.type)
1334: printf(" (%s)",smb_netaddr(&msg.to_net));
1335: printf("\nFrom : %s",msg.from);
1336: if(msg.from_net.type)
1337: printf(" (%s)",smb_netaddr(&msg.from_net));
1338: printf("\nDate : %.24s %s"
1339: ,my_timestr((time_t*)&msg.hdr.when_written.time)
1340: ,smb_zonestr(msg.hdr.when_written.zone,NULL));
1341:
1342: printf("\n\n");
1343:
1344: if((inbuf=smb_getmsgtxt(&smb,&msg,GETMSGTXT_ALL))!=NULL) {
1345: printf("%s",inbuf);
1346: free(inbuf);
1347: }
1348:
1349: i=smb_unlockmsghdr(&smb,&msg);
1350: if(i) {
1351: fprintf(errfp,"\n%s!smb_unlockmsghdr returned %d: %s\n"
1352: ,beep,i,smb.last_error);
1353: break;
1354: }
1355: smb_freemsgmem(&msg);
1356: }
1357: domsg=1;
1358: printf("\nReading %s (?=Menu): ",smb.file);
1359: switch(toupper(getch())) {
1360: case '?':
1361: printf("\n"
1362: "\n"
1363: "(R)e-read current message\n"
1364: "(L)ist messages\n"
1365: "(T)en more titles\n"
1366: "(V)iew message headers\n"
1367: "(Q)uit\n"
1368: "(+/-) Forward/Backward\n"
1369: "\n");
1370: domsg=0;
1371: break;
1372: case 'Q':
1373: printf("Quit\n");
1374: done=1;
1375: break;
1376: case 'R':
1377: printf("Re-read\n");
1378: break;
1379: case '-':
1380: printf("Backwards\n");
1381: if(msg.offset)
1382: msg.offset--;
1383: break;
1384: case 'T':
1385: printf("Ten titles\n");
1386: listmsgs(msg.offset+2,10);
1387: msg.offset+=10;
1388: domsg=0;
1389: break;
1390: case 'L':
1391: printf("List messages\n");
1392: listmsgs(1,-1);
1393: domsg=0;
1394: break;
1395: case 'V':
1396: printf("View message headers\n");
1397: viewmsgs(1,-1);
1398: domsg=0;
1399: break;
1400: case CR:
1401: case '+':
1402: printf("Next\n");
1403: msg.offset++;
1404: break;
1405: }
1406: }
1407: }
1408:
1409: short str2tzone(const char* str)
1410: {
1411: char tmp[32];
1412: short zone;
1413:
1414: if(isdigit(*str) || *str=='-' || *str=='+') { /* [+|-]HHMM format */
1415: if(*str=='+') str++;
1416: sprintf(tmp,"%.*s",*str=='-'? 3:2,str);
1417: zone=atoi(tmp)*60;
1418: str+=(*str=='-') ? 3:2;
1419: if(zone<0)
1420: zone-=atoi(str);
1421: else
1422: zone+=atoi(str);
1423: return zone;
1424: }
1425: if(!stricmp(str,"EST") || !stricmp(str,"Eastern Standard Time"))
1426: return (short)EST;
1427: if(!stricmp(str,"EDT") || !stricmp(str,"Eastern Daylight Time"))
1428: return (short)EDT;
1429: if(!stricmp(str,"CST") || !stricmp(str,"Central Standard Time"))
1430: return (short)CST;
1431: if(!stricmp(str,"CDT") || !stricmp(str,"Central Daylight Time"))
1432: return (short)CDT;
1433: if(!stricmp(str,"MST") || !stricmp(str,"Mountain Standard Time"))
1434: return (short)MST;
1435: if(!stricmp(str,"MDT") || !stricmp(str,"Mountain Daylight Time"))
1436: return (short)MDT;
1437: if(!stricmp(str,"PST") || !stricmp(str,"Pacific Standard Time"))
1438: return (short)PST;
1439: if(!stricmp(str,"PDT") || !stricmp(str,"Pacific Daylight Time"))
1440: return (short)PDT;
1441:
1442: return 0; /* UTC */
1443: }
1444:
1445: /***************/
1446: /* Entry point */
1447: /***************/
1448: int main(int argc, char **argv)
1449: {
1450: char cmd[128]="",*p;
1451: char path[MAX_PATH+1];
1452: char* to=NULL;
1453: char* to_number=NULL;
1454: char* to_address=NULL;
1455: char* from=NULL;
1456: char* from_number=NULL;
1457: char* subj=NULL;
1458: FILE* fp;
1459: int i,j,x,y;
1460: long count=0;
1461: BOOL create=FALSE;
1462: time_t now;
1463: struct tm* tm;
1464:
1465: setvbuf(stdout,0,_IONBF,0);
1466:
1467: errfp=stderr;
1468: if((nulfp=fopen(_PATH_DEVNULL,"w+"))==NULL) {
1469: perror(_PATH_DEVNULL);
1470: bail(-1);
1471: }
1472: if(isatty(fileno(stderr)))
1473: statfp=stderr;
1474: else /* if redirected, don't send status messages to stderr */
1475: statfp=nulfp;
1476:
1477: sscanf("$Revision: 1.93 $", "%*s %s", revision);
1478:
1479: DESCRIBE_COMPILER(compiler);
1480:
1481: smb.file[0]=0;
1482: fprintf(statfp,"\nSMBUTIL v%s-%s (rev %s) SMBLIB %s - Synchronet Message Base "\
1483: "Utility\n\n"
1484: ,SMBUTIL_VER
1485: ,PLATFORM_DESC
1486: ,revision
1487: ,smb_lib_ver()
1488: );
1489:
1490: /* Automatically detect the system time zone (if possible) */
1491: tzset();
1492: now=time(NULL);
1493: if((tm=localtime(&now))!=NULL) {
1494: if(tm->tm_isdst<=0)
1495: tzone=str2tzone(tzname[0]);
1496: else
1497: tzone=str2tzone(tzname[1]);
1498: }
1499:
1500: for(x=1;x<argc && x>0;x++) {
1501: if(
1502: #ifndef __unix__
1503: argv[x][0]=='/' || /* for backwards compatibilty */
1504: #endif
1505: argv[x][0]=='-') {
1506: if(isdigit(argv[x][1])) {
1507: count=strtol(argv[x]+1,NULL,10);
1508: continue;
1509: }
1510: for(j=1;argv[x][j];j++)
1511: switch(toupper(argv[x][j])) {
1512: case 'A':
1513: mode|=NOANALYSIS;
1514: break;
1515: case 'I':
1516: mode|=NOCRC;
1517: break;
1518: case 'D':
1519: to="All";
1520: to_number="1";
1521: from="Sysop";
1522: from_number="1";
1523: subj="Announcement";
1524: break;
1525: case 'Z':
1526: tzone=str2tzone(argv[x]+j+1);
1527: j=strlen(argv[x])-1;
1528: break;
1529: case 'C':
1530: create=TRUE;
1531: break;
1532: case 'T':
1533: to=argv[x]+j+1;
1534: j=strlen(argv[x])-1;
1535: break;
1536: case 'U':
1537: to_number=argv[x]+j+1;
1538: j=strlen(argv[x])-1;
1539: break;
1540: case 'N':
1541: to_address=argv[x]+j+1;
1542: j=strlen(argv[x])-1;
1543: break;
1544: case 'F':
1545: from=argv[x]+j+1;
1546: j=strlen(argv[x])-1;
1547: break;
1548: case 'E':
1549: from_number=argv[x]+j+1;
1550: j=strlen(argv[x])-1;
1551: break;
1552: case 'S':
1553: subj=argv[x]+j+1;
1554: j=strlen(argv[x])-1;
1555: break;
1556: case 'O':
1557: errfp=stdout;
1558: break;
1559: case 'L':
1560: xlat=XLAT_LZH;
1561: break;
1562: case 'P':
1563: pause_on_exit=TRUE;
1564: break;
1565: case '!':
1566: pause_on_error=TRUE;
1567: break;
1568: case 'B':
1569: beep="\a";
1570: break;
1571: default:
1572: printf("\nUnknown opt '%c'\n",argv[x][j]);
1573: case '?':
1574: printf("%s",usage);
1575: bail(1);
1576: break;
1577: }
1578: }
1579: else {
1580: if(!cmd[0])
1581: SAFECOPY(cmd,argv[x]);
1582: else {
1583: SAFECOPY(smb.file,argv[x]);
1584: if((p=getfext(smb.file))!=NULL && stricmp(p,".shd")==0)
1585: *p=0; /* Chop off .shd extension, if supplied on command-line */
1586:
1587: sprintf(path,"%s.shd",smb.file);
1588: if(!fexistcase(path) && !create) {
1589: fprintf(errfp,"\n%s doesn't exist (use -c to create)\n",path);
1590: bail(1);
1591: }
1592: smb.retry_time=30;
1593: fprintf(statfp,"Opening %s\r\n",smb.file);
1594: if((i=smb_open(&smb))!=0) {
1595: fprintf(errfp,"\n%s!Error %d (%s) opening %s message base\n"
1596: ,beep,i,smb.last_error,smb.file);
1597: bail(1);
1598: }
1599: if(!filelength(fileno(smb.shd_fp))) {
1600: if(!create) {
1601: printf("Empty\n");
1602: smb_close(&smb);
1603: continue;
1604: }
1605: smb.status.max_msgs=strtoul(cmd+1,NULL,0);
1606: smb.status.max_crcs=count;
1607: if((i=smb_create(&smb))!=0) {
1608: smb_close(&smb);
1609: printf("!Error %d (%s) creating %s\n",i,smb.last_error,smb.file);
1610: continue;
1611: }
1612: }
1613: for(y=0;cmd[y];y++)
1614: switch(toupper(cmd[y])) {
1615: case 'I':
1616: case 'E':
1617: case 'N':
1618: if(cmd[1]!=0) {
1619: if((fp=fopen(cmd+1,"r"))==NULL) {
1620: fprintf(errfp,"\n%s!Error %d opening %s\n"
1621: ,beep,errno,cmd+1);
1622: bail(1);
1623: }
1624: } else
1625: fp=stdin;
1626: i=smb_locksmbhdr(&smb);
1627: if(i) {
1628: fprintf(errfp,"\n%s!smb_locksmbhdr returned %d: %s\n"
1629: ,beep,i,smb.last_error);
1630: return(1);
1631: }
1632: postmsg((char)toupper(cmd[y]),to,to_number,to_address,from,from_number,subj,fp);
1633: fclose(fp);
1634: y=strlen(cmd)-1;
1635: break;
1636: case 'S':
1637: showstatus();
1638: break;
1639: case 'C':
1640: config();
1641: break;
1642: case 'L':
1643: listmsgs(atol(cmd+1),count);
1644: y=strlen(cmd)-1;
1645: break;
1646: case 'X':
1647: dumpindex(atol(cmd+1),count);
1648: y=strlen(cmd)-1;
1649: break;
1650: case 'P':
1651: case 'D':
1652: if((i=smb_lock(&smb))!=0) {
1653: fprintf(errfp,"\n%s!smb_lock returned %d: %s\n"
1654: ,beep,i,smb.last_error);
1655: return(i);
1656: }
1657: switch(toupper(cmd[y])) {
1658: case 'P':
1659: packmsgs(atol(cmd+y+1));
1660: break;
1661: case 'D':
1662: delmsgs();
1663: break;
1664: }
1665: smb_unlock(&smb);
1666: y=strlen(cmd)-1;
1667: break;
1668: case 'R':
1669: readmsgs(atol(cmd+1));
1670: y=strlen(cmd)-1;
1671: break;
1672: case 'V':
1673: viewmsgs(atol(cmd+1),count);
1674: y=strlen(cmd)-1;
1675: break;
1676: case 'H':
1677: dump_hashes();
1678: break;
1679: case 'M':
1680: maint();
1681: break;
1682: default:
1683: printf("%s",usage);
1684: break;
1685: }
1686: smb_close(&smb);
1687: }
1688: }
1689: }
1690: if(!cmd[0])
1691: printf("%s",usage);
1692:
1693: bail(0);
1694:
1695: return(-1); /* never gets here */
1696: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.