smbutil.c 41.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* smbutil.c */

/* Synchronet message base (SMB) utility */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
11
 * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html		*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

rswindell's avatar
rswindell committed
38
#define SMBUTIL_VER "2.32"
39
40
char	revision[16];
char	compiler[32];
41
42

#define NOANALYSIS		(1L<<0)
43
#define NOCRC			(1L<<1)
44
45
46
47
48
49
50

#ifdef __WATCOMC__
	#define ffblk find_t
    #define findfirst(x,y,z) _dos_findfirst(x,z,y)
	#define findnext(x) _dos_findnext(x)
#endif

51
52
53
54
55
56
#if defined(_WIN32)
	#include <ctype.h>	/* isdigit() */
	#include <conio.h>	/* getch() */
#endif

/* ANSI */
57
#include <stdio.h>
rswindell's avatar
rswindell committed
58
59
60
61
#include <time.h>		/* time */
#include <errno.h>		/* errno */
#include <string.h>		/* strrchr */
#include <ctype.h>		/* toupper */
62

63
#include "sbbs.h"
64
#include "genwrap.h"	/* stricmp */
rswindell's avatar
rswindell committed
65
#include "dirwrap.h"	/* fexist */
rswindell's avatar
rswindell committed
66
#include "conwrap.h"	/* getch */
67
#include "filewrap.h"
68
#include "smblib.h"
69
#include "crc32.h"
70
#include "gen_defs.h"	/* MAX_PATH */
71
72
73
74
75

#ifdef __WATCOMC__
	#include <dos.h>
#endif

76
/* gets is dangerous */
77
#define gets(str)  fgets((str), sizeof(str), stdin)
78

79
80
81
82
83
84
/********************/
/* Global variables */
/********************/

smb_t smb;
ulong mode=0L;
85
ushort tzone=0;
86
87
88
89
90
91

/************************/
/* Program usage/syntax */
/************************/

char *usage=
92
"usage: smbutil [-opts] cmd <filespec.shd>\n"
93
94
95
96
97
"\n"
"cmd:\n"
"       l[n] = list msgs starting at number n\n"
"       r[n] = read msgs starting at number n\n"
"       v[n] = view msg headers starting at number n\n"
98
99
100
"       i[f] = import msg from text file f (or use stdin)\n"
"       e[f] = import e-mail from text file f (or use stdin)\n"
"       n[f] = import netmail from text file f (or use stdin)\n"
101
102
103
104
105
"       s    = display msg base status\n"
"       c    = change msg base status\n"
"       m    = maintain msg base - delete old msgs and msgs over max\n"
"       p[k] = pack msg base (k specifies minimum packable Kbytes)\n"
"opts:\n"
rswindell's avatar
rswindell committed
106
"       c    = create message base if it doesn't exist\n"
107
"       a    = always pack msg base (disable compression analysis)\n"
108
"       i    = ignore duplicate messages (do not store CRC)\n"
109
"       d    = use default values (no prompt) for to, from, and subject\n"
110
111
112
113
114
115
"       t<s> = set 'to' user name for imported message\n"
"       n<s> = set 'to' netmail address for imported message\n"
"       u<s> = set 'to' user number for imported message\n"
"       f<s> = set 'from' user name for imported message\n"
"       e<s> = set 'from' user number for imported message\n"
"       s<s> = set 'subject' for imported message\n"
116
"       z[n] = set time zone (n=min +/- from UT or 'EST','EDT','CST',etc)\n"
117
"       #    = set number of messages to view/list (e.g. -1)\n"
118
119
;

120
121
122
123
124
125
/*****************************************************************************/
// Expands Unix LF to CRLF
/*****************************************************************************/
ulong lf_expand(BYTE* inbuf, ulong inlen, BYTE* outbuf)
{
	ulong	i,j;
rswindell's avatar
rswindell committed
126

127
128
129
130
131
132
133
	for(i=j=0;i<inlen;i++) {
		if(inbuf[i]=='\n' && (!i || inbuf[i-1]!='\r'))
			outbuf[j++]='\r';
		outbuf[j++]=inbuf[i];
	}
	return(j);
}
rswindell's avatar
rswindell committed
134

135
136
137
/****************************************************************************/
/* Adds a new message to the message base									*/
/****************************************************************************/
138
139
void postmsg(char type, char* to, char* to_number, char* to_address, 
			 char* from, char* from_number, char* subject, FILE* fp)
140
{
141
142
143
144
	char	str[128];
	char	buf[128];
	char	pad=0;
	char*	msgtxt=NULL;
145
	char*	newtxt;
146
	long	msgtxtlen;
147
	ushort	xlat,net;
148
149
150
	int 	i;
	long	l,length;
	ulong	offset,crc;
151
	ushort		agent=AGENT_SMBUTIL;
152
153
	smbmsg_t	msg;

154
155
156
157
158
159
160
	/* Read message text from stream (file or stdin) */
	msgtxtlen=0;
	while(!feof(fp)) {
		i=fread(buf,1,sizeof(buf),fp);
		if(i<1)
			break;
		if((msgtxt=(char*)realloc(msgtxt,msgtxtlen+i))==NULL) {
161
			fprintf(stderr,"\n\7malloc(%ld) failure\n",msgtxtlen+i);
162
163
164
165
166
167
			exit(1);
		}
		memcpy(msgtxt+msgtxtlen,buf,i);
		msgtxtlen+=i;
	}

168
169
170
171
172
173
174
175
176
177
	if((newtxt=(char*)malloc(msgtxtlen*2))==NULL) {
		fprintf(stderr,"\n\7malloc(%ld) failure\n",msgtxtlen*2);
		exit(1);
	}

	/* Expand LFs to CRLFs */
	msgtxtlen=lf_expand(msgtxt, msgtxtlen, newtxt);
	free(msgtxt);
	msgtxt=newtxt;

178
179
	/* Allocate space in message base */
	length=msgtxtlen+sizeof(xlat);	/* for translation string */
rswindell's avatar
rswindell committed
180
181
182
	if(!(smb.status.attr&SMB_HYPERALLOC)) {
		i=smb_open_da(&smb);
		if(i) {
183
			fprintf(stderr,"\n\7!smb_open_da returned %d: %s\n",i,smb.last_error);
184
185
			exit(1); 
		}
rswindell's avatar
rswindell committed
186
		offset=smb_allocdat(&smb,length,1);
187
188
		smb_close_da(&smb); 
	} else
rswindell's avatar
rswindell committed
189
190
191
192
		offset=smb_hallocdat(&smb);

	fseek(smb.sdt_fp,offset,SEEK_SET);
	xlat=XLAT_NONE;
193
194
	smb_fwrite(&smb,&xlat,sizeof(xlat),smb.sdt_fp);
	smb_fwrite(&smb,msgtxt,msgtxtlen,smb.sdt_fp);
195
	for(l=length;l%SDT_BLOCK_LEN;l++)
196
		smb_fwrite(&smb,&pad,sizeof(pad),smb.sdt_fp);
rswindell's avatar
rswindell committed
197
198
199
200
201
202
203
204
	fflush(smb.sdt_fp);

	memset(&msg,0,sizeof(smbmsg_t));
	msg.hdr.version=smb_ver();
	msg.hdr.when_written.time=time(NULL);
	msg.hdr.when_written.zone=tzone;
	msg.hdr.when_imported=msg.hdr.when_written;

205
	if(smb.status.max_crcs && !(mode&NOCRC)) {
206
207
208
209
		crc=0xffffffffUL;
		for(l=0;l<msgtxtlen;l++) 
			crc=ucrc32(msgtxt[l],crc);
		crc=~crc;
rswindell's avatar
rswindell committed
210
211
		i=smb_addcrc(&smb,crc);
		if(i) {
212
			fprintf(stderr,"\n\7!smb_addcrc returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
213
			smb_freemsgdat(&smb,offset,length,1);
214
215
216
			exit(1); 
		} 
	}
rswindell's avatar
rswindell committed
217
218
219

	msg.hdr.offset=offset;

220
221
	if(to==NULL) {
		printf("To User Name: ");
222
		fgets(str,sizeof(str),stdin); 
223
	} else
224
		SAFECOPY(str,to);
225

rswindell's avatar
rswindell committed
226
	truncsp(str);
227
	i=smb_hfield_str(&msg,RECIPIENT,str);
228
	if(i) {
229
		fprintf(stderr,"\n\7!smb_hfield returned %d: %s\n",i,smb.last_error);
230
		smb_freemsgdat(&smb,offset,length,1);
rswindell's avatar
rswindell committed
231
232
		exit(1); 
	}
rswindell's avatar
rswindell committed
233
234
235
	if(type=='E' || type=='N')
		smb.status.attr|=SMB_EMAIL;
	if(smb.status.attr&SMB_EMAIL) {
236
237
238
239
		if(to_number==NULL) {
			printf("To User Number (0=QWKnet or Internet): ");
			gets(str);
		} else
240
			SAFECOPY(str,to_number);
rswindell's avatar
rswindell committed
241
		truncsp(str);
242
		i=smb_hfield_str(&msg,RECIPIENTEXT,str);
243
		if(i) {
244
			fprintf(stderr,"\n\7!smb_hfield returned %d: %s\n",i,smb.last_error);
245
			smb_freemsgdat(&smb,offset,length,1);
246
247
			exit(1); 
		}
rswindell's avatar
rswindell committed
248
249
		msg.idx.to=atoi(str); 
	}
rswindell's avatar
rswindell committed
250
251
	else {
		strlwr(str);
252
		msg.idx.to=crc16(str,0); 
253
	}
rswindell's avatar
rswindell committed
254
255

	if(smb.status.attr&SMB_EMAIL && (type=='N' || !msg.idx.to)) {
256
257
258
259
		if(to_address==NULL) {
			printf("To Address: ");
			gets(str);
		} else
260
			SAFECOPY(str,to_address);
rswindell's avatar
rswindell committed
261
262
263
264
265
266
267
268
		truncsp(str);
		if(*str) {
			if(strchr(str,'.'))
				net=NET_INTERNET;
			else
				net=NET_QWK;
			i=smb_hfield(&msg,RECIPIENTNETTYPE,sizeof(net),&net);
			if(i) {
269
				fprintf(stderr,"\n\7!smb_hfield returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
270
				smb_freemsgdat(&smb,offset,length,1);
rswindell's avatar
rswindell committed
271
272
				exit(1); 
			}
273
			i=smb_hfield_str(&msg,RECIPIENTNETADDR,str);
rswindell's avatar
rswindell committed
274
			if(i) {
275
				fprintf(stderr,"\n\7!smb_hfield returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
276
				smb_freemsgdat(&smb,offset,length,1);
277
278
279
280
				exit(1); 
			} 
		} 
	}
rswindell's avatar
rswindell committed
281

282
283
284
285
	if(from==NULL) {
		printf("From User Name: ");
		gets(str);
	} else
286
		SAFECOPY(str,from);
rswindell's avatar
rswindell committed
287
	truncsp(str);
288
	i=smb_hfield_str(&msg,SENDER,str);
rswindell's avatar
rswindell committed
289
	if(i) {
290
		fprintf(stderr,"\n\7!smb_hfield returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
291
		smb_freemsgdat(&smb,offset,length,1);
rswindell's avatar
rswindell committed
292
293
		exit(1); 
	}
rswindell's avatar
rswindell committed
294
	if(smb.status.attr&SMB_EMAIL) {
295
296
297
298
		if(from_number==NULL) {
			printf("From User Number: ");
			gets(str);
		} else
299
			SAFECOPY(str,from_number);
rswindell's avatar
rswindell committed
300
		truncsp(str);
301
		i=smb_hfield_str(&msg,SENDEREXT,str);
302
		if(i) {
303
			fprintf(stderr,"\n\7!smb_hfield returned %d: %s\n",i,smb.last_error);
304
			smb_freemsgdat(&smb,offset,length,1);
305
306
307
308
			exit(1); 
		}
		msg.idx.from=atoi(str); 
	} else {
rswindell's avatar
rswindell committed
309
		strlwr(str);
310
		msg.idx.from=crc16(str,0); 
311
	}
312
	smb_hfield(&msg, SENDERAGENT, sizeof(agent), &agent);
rswindell's avatar
rswindell committed
313

314
315
316
317
	if(subject==NULL) {
		printf("Subject: ");
		gets(str);
	} else
318
		SAFECOPY(str,subject);
rswindell's avatar
rswindell committed
319
	truncsp(str);
320
	i=smb_hfield_str(&msg,SUBJECT,str);
321
	if(i) {
322
		fprintf(stderr,"\n\7!smb_hfield returned %d: %s\n",i,smb.last_error);
323
		smb_freemsgdat(&smb,offset,length,1);
324
325
		exit(1); 
	}
326
	msg.idx.subj=subject_crc(str);
rswindell's avatar
rswindell committed
327
328
329

	i=smb_dfield(&msg,TEXT_BODY,length);
	if(i) {
330
		fprintf(stderr,"\n\7!smb_dfield returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
331
		smb_freemsgdat(&smb,offset,length,1);
rswindell's avatar
rswindell committed
332
333
		exit(1); 
	}
rswindell's avatar
rswindell committed
334

335
	sprintf(str,"SMBUTIL %s-%s r%s %s %s"
336
337
338
339
340
341
		,SMBUTIL_VER
		,PLATFORM_DESC
		,revision
		,__DATE__
		,compiler
		);
342
	smb_hfield_str(&msg,FIDOPID,str);
343

rswindell's avatar
rswindell committed
344
345
346
	i=smb_addmsghdr(&smb,&msg,smb.status.attr&SMB_HYPERALLOC);

	if(i) {
347
		fprintf(stderr,"\n\7!smb_addmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
348
		smb_freemsgdat(&smb,offset,length,1);
rswindell's avatar
rswindell committed
349
350
		exit(1); 
	}
rswindell's avatar
rswindell committed
351
	smb_freemsgmem(&msg);
352

353
	free(msgtxt);
354
355
356
357
358
}

/****************************************************************************/
/* Shows the message base header											*/
/****************************************************************************/
359
void showstatus(void)
360
361
362
{
	int i;

rswindell's avatar
rswindell committed
363
364
	i=smb_locksmbhdr(&smb);
	if(i) {
365
		fprintf(stderr,"\n\7!smb_locksmbhdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
366
367
		return; 
	}
rswindell's avatar
rswindell committed
368
369
370
	i=smb_getstatus(&smb);
	smb_unlocksmbhdr(&smb);
	if(i) {
371
		fprintf(stderr,"\n\7!smb_getstatus returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
372
373
		return; 
	}
rswindell's avatar
rswindell committed
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
	printf("last_msg        =%lu\n"
		   "total_msgs      =%lu\n"
		   "header_offset   =%lu\n"
		   "max_crcs        =%lu\n"
		   "max_msgs        =%lu\n"
		   "max_age         =%u\n"
		   "attr            =%04Xh\n"
		   ,smb.status.last_msg
		   ,smb.status.total_msgs
		   ,smb.status.header_offset
		   ,smb.status.max_crcs
		   ,smb.status.max_msgs
		   ,smb.status.max_age
		   ,smb.status.attr
		   );
389
390
391
392
393
}

/****************************************************************************/
/* Configure message base header											*/
/****************************************************************************/
394
void config(void)
395
396
397
398
{
	char max_msgs[128],max_crcs[128],max_age[128],header_offset[128],attr[128];
	int i;

rswindell's avatar
rswindell committed
399
400
	i=smb_locksmbhdr(&smb);
	if(i) {
401
		fprintf(stderr,"\n\7!smb_locksmbhdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
402
403
		return; 
	}
rswindell's avatar
rswindell committed
404
405
406
	i=smb_getstatus(&smb);
	smb_unlocksmbhdr(&smb);
	if(i) {
407
		fprintf(stderr,"\n\7!smb_getstatus returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
408
409
		return; 
	}
rswindell's avatar
rswindell committed
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
	printf("Header offset =%-5lu  New value (CR=No Change): "
		,smb.status.header_offset);
	gets(header_offset);
	printf("Max msgs      =%-5lu  New value (CR=No Change): "
		,smb.status.max_msgs);
	gets(max_msgs);
	printf("Max crcs      =%-5lu  New value (CR=No Change): "
		,smb.status.max_crcs);
	gets(max_crcs);
	printf("Max age       =%-5u  New value (CR=No Change): "
		,smb.status.max_age);
	gets(max_age);
	printf("Attributes    =%-5u  New value (CR=No Change): "
		,smb.status.attr);
	gets(attr);
	i=smb_locksmbhdr(&smb);
	if(i) {
427
		fprintf(stderr,"\n\7!smb_locksmbhdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
428
429
		return; 
	}
rswindell's avatar
rswindell committed
430
431
	i=smb_getstatus(&smb);
	if(i) {
432
		fprintf(stderr,"\n\7!smb_getstatus returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
433
		smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
434
435
		return; 
	}
rswindell's avatar
rswindell committed
436
437
438
439
440
441
442
443
444
445
446
	if(isdigit(max_msgs[0]))
		smb.status.max_msgs=atol(max_msgs);
	if(isdigit(max_crcs[0]))
		smb.status.max_crcs=atol(max_crcs);
	if(isdigit(max_age[0]))
		smb.status.max_age=atoi(max_age);
	if(isdigit(header_offset[0]))
		smb.status.header_offset=atol(header_offset);
	if(isdigit(attr[0]))
		smb.status.attr=atoi(attr);
	i=smb_putstatus(&smb);
447
	smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
448
	if(i)
449
		fprintf(stderr,"\n\7!smb_putstatus returned %d: %s\n",i,smb.last_error);
450
451
452
453
454
455
456
457
458
459
460
}

/****************************************************************************/
/* Lists messages' to, from, and subject                                    */
/****************************************************************************/
void listmsgs(ulong start, ulong count)
{
	int i;
	ulong l=0;
	smbmsg_t msg;

rswindell's avatar
rswindell committed
461
462
463
464
465
466
467
468
	if(!start)
		start=1;
	fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
	while(l<count) {
		if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
			break;
		i=smb_lockmsghdr(&smb,&msg);
		if(i) {
469
			fprintf(stderr,"\n\7!smb_lockmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
470
471
			break; 
		}
rswindell's avatar
rswindell committed
472
473
474
		i=smb_getmsghdr(&smb,&msg);
		smb_unlockmsghdr(&smb,&msg);
		if(i) {
475
			fprintf(stderr,"\n\7!smb_getmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
476
477
			break; 
		}
rswindell's avatar
rswindell committed
478
479
480
		printf("%4lu %-25.25s %-25.25s %.20s\n"
			,msg.hdr.number,msg.from,msg.to,msg.subj);
		smb_freemsgmem(&msg);
rswindell's avatar
rswindell committed
481
482
		l++; 
	}
483
484
485
486
487
488
489
490
491
492
}

char *binstr(uchar *buf, ushort length)
{
	static char str[512];
	char tmp[128];
	int i;

	str[0]=0;
	for(i=0;i<length;i++)
493
494
		if(buf[i] && (buf[i]<' ' || buf[i]>=0x7f) 
			&& buf[i]!='\r' && buf[i]!='\n' && buf[i]!='\t')
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
			break;
	if(i==length)		/* not binary */
		return(buf);
	for(i=0;i<length;i++) {
		sprintf(tmp,"%02X ",buf[i]);
		strcat(str,tmp); 
		if(i>=100) {
			strcat(str,"...");
			break;
		}
	}
	return(str);
}

/****************************************************************************/
/* Generates a 24 character ASCII string that represents the time_t pointer */
/* Used as a replacement for ctime()                                        */
/****************************************************************************/
513
char *my_timestr(time_t *intime)
514
515
516
517
518
{
    static char str[256];
    char mer[3],hour;
    struct tm *gm;

rswindell's avatar
rswindell committed
519
520
521
	gm=localtime(intime);
	if(gm==NULL) {
		strcpy(str,"Invalid Time");
rswindell's avatar
rswindell committed
522
523
		return(str); 
	}
rswindell's avatar
rswindell committed
524
525
526
527
528
	if(gm->tm_hour>=12) {
		if(gm->tm_hour==12)
			hour=12;
		else
			hour=gm->tm_hour-12;
rswindell's avatar
rswindell committed
529
530
		strcpy(mer,"pm"); 
	}
rswindell's avatar
rswindell committed
531
532
533
534
535
	else {
		if(gm->tm_hour==0)
			hour=12;
		else
			hour=gm->tm_hour;
rswindell's avatar
rswindell committed
536
537
		strcpy(mer,"am"); 
	}
rswindell's avatar
rswindell committed
538
539
540
541
	sprintf(str,"%s %s %02d %4d %02d:%02d %s"
		,wday[gm->tm_wday],mon[gm->tm_mon],gm->tm_mday,1900+gm->tm_year
		,hour,gm->tm_min,mer);
	return(str);
542
543
544
545
546
547
548
549
550
551
552
}

/****************************************************************************/
/* Displays message header information										*/
/****************************************************************************/
void viewmsgs(ulong start, ulong count)
{
	int i;
	ulong l=0;
	smbmsg_t msg;

rswindell's avatar
rswindell committed
553
554
555
556
557
558
559
560
	if(!start)
		start=1;
	fseek(smb.sid_fp,(start-1L)*sizeof(idxrec_t),SEEK_SET);
	while(l<count) {
		if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
			break;
		i=smb_lockmsghdr(&smb,&msg);
		if(i) {
561
			fprintf(stderr,"\n\7!smb_lockmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
562
563
			break; 
		}
rswindell's avatar
rswindell committed
564
565
566
		i=smb_getmsghdr(&smb,&msg);
		smb_unlockmsghdr(&smb,&msg);
		if(i) {
567
			fprintf(stderr,"\n\7!smb_getmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
568
569
			break; 
		}
570

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
		printf("%-16.16s %ld\n"		,"index record",ftell(smb.sid_fp)/sizeof(idxrec_t));
		printf("%-16.16s %ld\n"		,"number"			,msg.hdr.number);

		/* convenience strings */
		if(msg.subj)
			printf("%-16.16s %s\n"	,"subject"			,msg.subj);
		if(msg.to) {
			printf("%-16.16s %s"	,"to"				,msg.to);
			if(msg.to_net.addr && strchr(msg.to,'@')==NULL)
				printf(" (%s)",net_addr(&msg.to_net)); 
			if(msg.to_ext)
				printf(" #%s",msg.to_ext);
			printf("\n");
		}
		if(msg.from) {
			printf("%-16.16s %s"	,"from"				,msg.from);
			if(msg.from_net.addr && strchr(msg.from,'@')==NULL)
				printf(" (%s)",net_addr(&msg.from_net)); 
			if(msg.from_ext)
				printf(" #%s",msg.from_ext);
			printf("\n");
		}
		if(msg.replyto) {
			printf("%-16.16s %s"	,"reply-to"			,msg.replyto);
			if(msg.replyto_net.addr && strchr(msg.replyto,'@')==NULL)
				printf(" (%s)",net_addr(&msg.replyto_net)); 
			if(msg.replyto_ext)
				printf(" #%s",msg.replyto_ext);
			printf("\n");
		}
		if(msg.summary)
			printf("%-16.16s %s\n"	,"summary"			,msg.summary);

		/* optional fixed fields */
		if(msg.hdr.thread_orig)
			printf("%-16.16s %ld\n"	,"thread_orig"		,msg.hdr.thread_orig);
		if(msg.hdr.thread_next)
			printf("%-16.16s %ld\n"	,"thread_next"		,msg.hdr.thread_next);
		if(msg.hdr.thread_first)
			printf("%-16.16s %ld\n"	,"thread_first"		,msg.hdr.thread_first);
		if(msg.hdr.delivery_attempts)
			printf("%-16.16s %hu\n"	,"delivery_attempts",msg.hdr.delivery_attempts);
		if(msg.hdr.times_downloaded)
			printf("%-16.16s %lu\n"	,"times_downloaded"	,msg.hdr.times_downloaded);
		if(msg.hdr.last_downloaded)
			printf("%-16.16s %s\n"	,"last_downloaded"	,my_timestr((time_t*)&msg.hdr.last_downloaded));

		/* convenience integers */
		if(msg.cost)
			printf("%-16.16s %lu\n"	,"cost"				,msg.cost);
		if(msg.priority)
			printf("%-16.16s %lu\n"	,"priority"			,msg.priority);
		if(msg.expiration)
			printf("%-16.16s %s\n"	,"expiration"	
				,my_timestr((time_t *)&msg.expiration));

		printf("%-16.16s %s %s\n"	,"when_written"	
			,my_timestr((time_t *)&msg.hdr.when_written.time), zonestr(msg.hdr.when_written.zone));
		printf("%-16.16s %s %s\n"	,"when_imported"	
			,my_timestr((time_t *)&msg.hdr.when_imported.time), zonestr(msg.hdr.when_imported.zone));
		printf("%-16.16s %04Xh\n"	,"type"				,msg.hdr.type);
		printf("%-16.16s %04Xh\n"	,"version"			,msg.hdr.version);
		printf("%-16.16s %04Xh\n"	,"attr"				,msg.hdr.attr);
		printf("%-16.16s %08lXh\n"	,"auxattr"			,msg.hdr.auxattr);
		printf("%-16.16s %08lXh\n"	,"netattr"			,msg.hdr.netattr);
		printf("%-16.16s %06lXh\n"	,"header offset"	,msg.idx.offset);
		printf("%-16.16s %u\n"		,"header length"	,msg.hdr.length);

		/* variable fields */
		for(i=0;i<msg.total_hfields;i++)
			printf("%-16.16s %s\n"
				,smb_hfieldtype(msg.hfield[i].type)
				,binstr((uchar *)msg.hfield_dat[i],msg.hfield[i].length));
rswindell's avatar
rswindell committed
644

645
		printf("%-16.16s %06lXh\n"	,"data offset"		,msg.hdr.offset);
rswindell's avatar
rswindell committed
646
		for(i=0;i<msg.hdr.total_dfields;i++)
647
648
649
650
651
			printf("data field[%u]    %s, offset %lu, length %lu\n"
				,i
				,smb_dfieldtype(msg.dfield[i].type)
				,msg.dfield[i].offset
				,msg.dfield[i].length);
rswindell's avatar
rswindell committed
652
653
654

		printf("\n");
		smb_freemsgmem(&msg);
rswindell's avatar
rswindell committed
655
656
		l++; 
	}
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
}

/****************************************************************************/
/* Maintain message base - deletes messages older than max age (in days)	*/
/* or messages that exceed maximum											*/
/****************************************************************************/
void maint(void)
{
	int i;
	ulong l,m,n,f,flagged=0;
	time_t now;
	smbmsg_t msg;
	idxrec_t HUGE16 *idx;

	printf("Maintaining %s\r\n",smb.file);
	now=time(NULL);
	i=smb_locksmbhdr(&smb);
	if(i) {
675
		fprintf(stderr,"\n\7!smb_locksmbhdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
676
677
		return; 
	}
678
679
680
	i=smb_getstatus(&smb);
	if(i) {
		smb_unlocksmbhdr(&smb);
681
		fprintf(stderr,"\n\7!smb_getstatus returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
682
683
		return; 
	}
684
685
686
	if(!smb.status.total_msgs) {
		smb_unlocksmbhdr(&smb);
		printf("Empty\n");
rswindell's avatar
rswindell committed
687
688
		return; 
	}
689
690
691
692
	printf("Loading index...\n");
	if((idx=(idxrec_t *)LMALLOC(sizeof(idxrec_t)*smb.status.total_msgs))
		==NULL) {
		smb_unlocksmbhdr(&smb);
693
		fprintf(stderr,"\n\7!Error allocating %lu bytes of memory\n"
694
			,sizeof(idxrec_t)*smb.status.total_msgs);
rswindell's avatar
rswindell committed
695
696
		return; 
	}
697
698
699
700
701
	fseek(smb.sid_fp,0L,SEEK_SET);
	for(l=0;l<smb.status.total_msgs;l++) {
		printf("%lu of %lu\r"
			,l+1,smb.status.total_msgs);
		if(!fread(&idx[l],1,sizeof(idxrec_t),smb.sid_fp))
rswindell's avatar
rswindell committed
702
703
			break; 
	}
704
705
706
707
	printf("\nDone.\n\n");

	printf("Scanning for pre-flagged messages...\n");
	for(m=0;m<l;m++) {
rswindell's avatar
rswindell committed
708
		printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
709
		if(idx[m].attr&MSG_DELETE)
rswindell's avatar
rswindell committed
710
711
			flagged++; 
	}
712
713
714
715
716
717
	printf("\r100%% (%lu pre-flagged for deletion)\n",flagged);

	if(smb.status.max_age) {
		printf("Scanning for messages more than %u days old...\n"
			,smb.status.max_age);
		for(m=f=0;m<l;m++) {
rswindell's avatar
rswindell committed
718
			printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
719
720
721
722
723
724
			if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
				continue;
			if((ulong)now>idx[m].time && (now-idx[m].time)/(24L*60L*60L)
				>smb.status.max_age) {
				f++;
				flagged++;
rswindell's avatar
rswindell committed
725
726
727
728
729
				idx[m].attr|=MSG_DELETE; 
			} 
		}  /* mark for deletion */
		printf("\r100%% (%lu flagged for deletion)\n",f); 
	}
730
731
732

	printf("Scanning for read messages to be killed...\n");
	for(m=f=0;m<l;m++) {
rswindell's avatar
rswindell committed
733
		printf("\r%2lu%%",m ? (long)(100.0/((float)l/m)) : 0);
734
735
736
737
738
		if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
			continue;
		if((idx[m].attr&(MSG_READ|MSG_KILLREAD))==(MSG_READ|MSG_KILLREAD)) {
			f++;
			flagged++;
rswindell's avatar
rswindell committed
739
740
741
			idx[m].attr|=MSG_DELETE; 
		} 
	}
742
743
	printf("\r100%% (%lu flagged for deletion)\n",f);

744
	if(smb.status.max_msgs && l-flagged>smb.status.max_msgs) {
745
746
747
748
749
750
		printf("Flagging excess messages for deletion...\n");
		for(m=n=0,f=flagged;l-flagged>smb.status.max_msgs && m<l;m++) {
			if(idx[m].attr&(MSG_PERMANENT|MSG_DELETE))
				continue;
			printf("%lu of %lu\r",++n,(l-f)-smb.status.max_msgs);
			flagged++;
rswindell's avatar
rswindell committed
751
752
753
754
			idx[m].attr|=MSG_DELETE; 
		}			/* mark for deletion */
		printf("\nDone.\n\n"); 
	}
755
756
757
758

	if(!flagged) {				/* No messages to delete */
		LFREE(idx);
		smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
759
760
		return; 
	}
761
762
763
764
765
766
767
768

	if(!(mode&NOANALYSIS)) {

		printf("Freeing allocated header and data blocks for deleted messages...\n");
		if(!(smb.status.attr&SMB_HYPERALLOC)) {
			i=smb_open_da(&smb);
			if(i) {
				smb_unlocksmbhdr(&smb);
769
				fprintf(stderr,"\n\7!smb_open_da returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
770
771
				exit(1); 
			}
772
773
774
			i=smb_open_ha(&smb);
			if(i) {
				smb_unlocksmbhdr(&smb);
775
				fprintf(stderr,"\n\7!smb_open_ha returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
776
777
778
				exit(1); 
			} 
		}
779
780
781
782
783
784
785

		for(m=n=0;m<l;m++) {
			if(idx[m].attr&MSG_DELETE) {
				printf("%lu of %lu\r",++n,flagged);
				msg.idx=idx[m];
				msg.hdr.number=msg.idx.number;
				if((i=smb_getmsgidx(&smb,&msg))!=0) {
786
					fprintf(stderr,"\n\7!smb_getmsgidx returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
787
788
					continue; 
				}
789
790
				i=smb_lockmsghdr(&smb,&msg);
				if(i) {
791
					fprintf(stderr,"\n\7!smb_lockmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
792
793
					break; 
				}
794
795
				if((i=smb_getmsghdr(&smb,&msg))!=0) {
					smb_unlockmsghdr(&smb,&msg);
796
					fprintf(stderr,"\n\7!smb_getmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
797
798
					break; 
				}
799
800
801
802
				msg.hdr.attr|=MSG_DELETE;			/* mark header as deleted */
				if((i=smb_putmsg(&smb,&msg))!=0) {
					smb_freemsgmem(&msg);
					smb_unlockmsghdr(&smb,&msg);
803
					fprintf(stderr,"\n\7!smb_putmsg returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
804
805
					break; 
				}
806
807
808
				smb_unlockmsghdr(&smb,&msg);
				if((i=smb_freemsg(&smb,&msg))!=0) {
					smb_freemsgmem(&msg);
809
					fprintf(stderr,"\n\7!smb_freemsg returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
810
811
812
813
814
					break; 
				}
				smb_freemsgmem(&msg); 
			} 
		}
815
816
		if(!(smb.status.attr&SMB_HYPERALLOC)) {
			smb_close_ha(&smb);
rswindell's avatar
rswindell committed
817
818
819
820
			smb_close_da(&smb); 
		}
		printf("\nDone.\n\n"); 
	}
821
822
823
824
825
826
827
828
829

	printf("Re-writing index...\n");
	rewind(smb.sid_fp);
	if(chsize(fileno(smb.sid_fp),0L))
		printf("chsize failed!\n");
	for(m=n=0;m<l;m++) {
		if(idx[m].attr&MSG_DELETE)
			continue;
		printf("%lu of %lu\r",++n,l-flagged);
rswindell's avatar
rswindell committed
830
831
		fwrite(&idx[m],sizeof(idxrec_t),1,smb.sid_fp); 
	}
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
	printf("\nDone.\n\n");
	fflush(smb.sid_fp);

	LFREE(idx);
	smb.status.total_msgs-=flagged;
	smb_putstatus(&smb);
	smb_unlocksmbhdr(&smb);
}


typedef struct {
	ulong old,new;
	} datoffset_t;

/****************************************************************************/
/* Removes all unused blocks from SDT and SHD files 						*/
/****************************************************************************/
void packmsgs(ulong packable)
{
	uchar str[128],buf[SDT_BLOCK_LEN],ch,fname[128],tmpfname[128];
	int i,size;
	ulong l,m,n,datoffsets=0,length,total,now;
	FILE *tmp_sdt,*tmp_shd,*tmp_sid;
855
	BOOL		error=FALSE;
856
857
858
859
	smbhdr_t	hdr;
	smbmsg_t	msg;
	datoffset_t *datoffset=NULL;

rswindell's avatar
rswindell committed
860
861
862
	now=time(NULL);
	printf("Packing %s\n",smb.file);
	i=smb_locksmbhdr(&smb);
863
	if(i) {
864
		fprintf(stderr,"\n\7!smb_locksmbhdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
865
866
		return; 
	}
rswindell's avatar
rswindell committed
867
	i=smb_getstatus(&smb);
868
869
	if(i) {
		smb_unlocksmbhdr(&smb);
870
		fprintf(stderr,"\n\7!smb_getstatus returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
871
872
		return; 
	}
rswindell's avatar
rswindell committed
873

874
	if(!(smb.status.attr&SMB_HYPERALLOC)) {
rswindell's avatar
rswindell committed
875
876
877
		i=smb_open_ha(&smb);
		if(i) {
			smb_unlocksmbhdr(&smb);
878
			fprintf(stderr,"\n\7!smb_open_ha returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
879
880
			return; 
		}
rswindell's avatar
rswindell committed
881
882
883
884
		i=smb_open_da(&smb);
		if(i) {
			smb_unlocksmbhdr(&smb);
			smb_close_ha(&smb);
885
			fprintf(stderr,"\n\7!smb_open_da returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
886
887
888
			return; 
		} 
	}
889

rswindell's avatar
rswindell committed
890
891
892
893
894
895
896
897
898
899
900
901
902
903
	if(!smb.status.total_msgs) {
		printf("Empty\n");
		rewind(smb.shd_fp);
		chsize(fileno(smb.shd_fp),smb.status.header_offset);
		rewind(smb.sdt_fp);
		chsize(fileno(smb.sdt_fp),0L);
		rewind(smb.sid_fp);
		chsize(fileno(smb.sid_fp),0L);
		if(!(smb.status.attr&SMB_HYPERALLOC)) {
			rewind(smb.sha_fp);
			chsize(fileno(smb.sha_fp),0L);
			rewind(smb.sda_fp);
			chsize(fileno(smb.sda_fp),0L);
			smb_close_ha(&smb);
rswindell's avatar
rswindell committed
904
905
			smb_close_da(&smb); 
		}
rswindell's avatar
rswindell committed
906
		smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
907
908
		return; 
	}
909
910


rswindell's avatar
rswindell committed
911
912
	if(!(smb.status.attr&SMB_HYPERALLOC) && !(mode&NOANALYSIS)) {
		printf("Analyzing data blocks...\n");
913

rswindell's avatar
rswindell committed
914
		length=filelength(fileno(smb.sda_fp));
915

rswindell's avatar
rswindell committed
916
917
		fseek(smb.sda_fp,0L,SEEK_SET);
		for(l=m=0;l<length;l+=2) {
rswindell's avatar
rswindell committed
918
			printf("\r%2lu%%  ",l ? (long)(100.0/((float)length/l)) : 0);
rswindell's avatar
rswindell committed
919
920
921
922
			i=0;
			if(!fread(&i,2,1,smb.sda_fp))
				break;
			if(!i)
rswindell's avatar
rswindell committed
923
924
				m++; 
		}
925

rswindell's avatar
rswindell committed
926
		printf("\rAnalyzing header blocks...\n");
927

rswindell's avatar
rswindell committed
928
		length=filelength(fileno(smb.sha_fp));
929

rswindell's avatar
rswindell committed
930
931
		fseek(smb.sha_fp,0L,SEEK_SET);
		for(l=n=0;l<length;l++) {
rswindell's avatar
rswindell committed
932
			printf("\r%2lu%%  ",l ? (long)(100.0/((float)length/l)) : 0);
rswindell's avatar
rswindell committed
933
934
935
936
			ch=0;
			if(!fread(&ch,1,1,smb.sha_fp))
				break;
			if(!ch)
rswindell's avatar
rswindell committed
937
938
				n++; 
		}
rswindell's avatar
rswindell committed
939
940
941
942
943
944

		if(!m && !n) {
			printf("\rAlready compressed.\n\n");
			smb_close_ha(&smb);
			smb_close_da(&smb);
			smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
945
946
			return; 
		}
947

rswindell's avatar
rswindell committed
948
		if(packable && (m*SDT_BLOCK_LEN)+(n*SHD_BLOCK_LEN)<packable*1024L) {
949
			printf("\rLess than %luk compressible bytes.\n\n",packable);
rswindell's avatar
rswindell committed
950
951
952
			smb_close_ha(&smb);
			smb_close_da(&smb);
			smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
953
954
			return; 
		}
rswindell's avatar
rswindell committed
955
956
957

		printf("\rCompressing %lu data blocks (%lu bytes)\n"
				 "        and %lu header blocks (%lu bytes)\n"
rswindell's avatar
rswindell committed
958
959
				  ,m,m*SDT_BLOCK_LEN,n,n*SHD_BLOCK_LEN); 
	}
rswindell's avatar
rswindell committed
960
961
962
963
964

	if(!(smb.status.attr&SMB_HYPERALLOC)) {
		rewind(smb.sha_fp);
		chsize(fileno(smb.sha_fp),0L);		/* Reset both allocation tables */
		rewind(smb.sda_fp);
rswindell's avatar
rswindell committed
965
966
		chsize(fileno(smb.sda_fp),0L); 
	}
rswindell's avatar
rswindell committed
967
968
969
970
971
972
973

	if(smb.status.attr&SMB_HYPERALLOC && !(mode&NOANALYSIS)) {
		printf("Analyzing %s\n",smb.file);

		length=filelength(fileno(smb.shd_fp));
		m=n=0;
		for(l=smb.status.header_offset;l<length;l+=size) {
rswindell's avatar
rswindell committed
974
			printf("\r%2lu%%  ",(long)(100.0/((float)length/l)));
rswindell's avatar
rswindell committed
975
976
977
978
			msg.idx.offset=l;
			if((i=smb_lockmsghdr(&smb,&msg))!=0) {
				printf("\n(%06lX) smb_lockmsghdr returned %d\n",l,i);
				size=SHD_BLOCK_LEN;
rswindell's avatar
rswindell committed
979
980
				continue; 
			}
rswindell's avatar
rswindell committed
981
982
983
984
			if((i=smb_getmsghdr(&smb,&msg))!=0) {
				smb_unlockmsghdr(&smb,&msg);
				m++;
				size=SHD_BLOCK_LEN;
rswindell's avatar
rswindell committed
985
986
				continue; 
			}
rswindell's avatar
rswindell committed
987
988
989
			smb_unlockmsghdr(&smb,&msg);
			if(msg.hdr.attr&MSG_DELETE) {
				m+=smb_hdrblocks(msg.hdr.length);
rswindell's avatar
rswindell committed
990
991
992
993
994
				n+=smb_datblocks(smb_getmsgdatlen(&msg)); 
			}
			size=smb_hdrblocks(smb_getmsghdrlen(&msg))*SHD_BLOCK_LEN;
			smb_freemsgmem(&msg); 
		}
rswindell's avatar
rswindell committed
995
996
997
998
999


		if(!m && !n) {
			printf("\rAlready compressed.\n\n");
			smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
1000
1001
			return; 
		}
rswindell's avatar
rswindell committed
1002
1003

		if(packable && (n*SDT_BLOCK_LEN)+(m*SHD_BLOCK_LEN)<packable*1024L) {
1004
			printf("\rLess than %luk compressible bytes.\n\n",packable);
rswindell's avatar
rswindell committed
1005
			smb_unlocksmbhdr(&smb);
rswindell's avatar
rswindell committed
1006
1007
			return; 
		}
rswindell's avatar
rswindell committed
1008
1009
1010

		printf("\rCompressing %lu data blocks (%lu bytes)\n"
				 "        and %lu header blocks (%lu bytes)\n"
rswindell's avatar
rswindell committed
1011
1012
				  ,n,n*SDT_BLOCK_LEN,m,m*SHD_BLOCK_LEN); 
	}
rswindell's avatar
rswindell committed
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023

	sprintf(fname,"%s.sd$",smb.file);
	tmp_sdt=fopen(fname,"wb");
	sprintf(fname,"%s.sh$",smb.file);
	tmp_shd=fopen(fname,"wb");
	sprintf(fname,"%s.si$",smb.file);
	tmp_sid=fopen(fname,"wb");
	if(!tmp_sdt || !tmp_shd || !tmp_sid) {
		smb_unlocksmbhdr(&smb);
		if(!(smb.status.attr&SMB_HYPERALLOC)) {
			smb_close_ha(&smb);
rswindell's avatar
rswindell committed
1024
1025
			smb_close_da(&smb); 
		}
1026
		fprintf(stderr,"\n\7!Error opening temp files\n");
rswindell's avatar
rswindell committed
1027
1028
		return; 
	}
rswindell's avatar
rswindell committed
1029
1030
1031
1032
1033
1034
1035
	setvbuf(tmp_sdt,NULL,_IOFBF,2*1024);
	setvbuf(tmp_shd,NULL,_IOFBF,2*1024);
	setvbuf(tmp_sid,NULL,_IOFBF,2*1024);
	if(!(smb.status.attr&SMB_HYPERALLOC)
		&& (datoffset=(datoffset_t *)LMALLOC(sizeof(datoffset_t)*smb.status.total_msgs))
		==NULL) {
		smb_unlocksmbhdr(&smb);
1036
1037
		smb_close_ha(&smb);
		smb_close_da(&smb);
rswindell's avatar
rswindell committed
1038
1039
1040
		fclose(tmp_sdt);
		fclose(tmp_shd);
		fclose(tmp_sid);
1041
		fprintf(stderr,"\n\7!Error allocating memory\n");
rswindell's avatar
rswindell committed
1042
1043
		return; 
	}
rswindell's avatar
rswindell committed
1044
1045
1046
1047
1048
1049
	fseek(smb.shd_fp,0L,SEEK_SET);
	fread(&hdr,1,sizeof(smbhdr_t),smb.shd_fp);
	fwrite(&hdr,1,sizeof(smbhdr_t),tmp_shd);
	fwrite(&(smb.status),1,sizeof(smbstatus_t),tmp_shd);
	for(l=sizeof(smbhdr_t)+sizeof(smbstatus_t);l<smb.status.header_offset;l++) {
		fread(&ch,1,1,smb.shd_fp);			/* copy additional base header records */
rswindell's avatar
rswindell committed
1050
1051
		fwrite(&ch,1,1,tmp_shd); 
	}
rswindell's avatar
rswindell committed
1052
1053
1054
1055
1056
1057
1058
1059
	fseek(smb.sid_fp,0L,SEEK_SET);
	total=0;
	for(l=0;l<smb.status.total_msgs;l++) {
		printf("%lu of %lu\r",l+1,smb.status.total_msgs);
		if(!fread(&msg.idx,1,sizeof(idxrec_t),smb.sid_fp))
			break;
		if(msg.idx.attr&MSG_DELETE) {
			printf("\nDeleted index.\n");
rswindell's avatar
rswindell committed
1060
1061
			continue; 
		}
rswindell's avatar
rswindell committed
1062
1063
		i=smb_lockmsghdr(&smb,&msg);
		if(i) {
1064
			fprintf(stderr,"\n\7!smb_lockmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
1065
1066
			continue; 
		}
rswindell's avatar
rswindell committed
1067
		i=smb_getmsghdr(&smb,&msg);
1068
		smb_unlockmsghdr(&smb,&msg);
rswindell's avatar
rswindell committed
1069
		if(i) {
1070
			fprintf(stderr,"\n\7!smb_getmsghdr returned %d: %s\n",i,smb.last_error);
rswindell's avatar
rswindell committed
1071
1072
			continue; 
		}
1073
		if(msg.hdr.attr&MSG_DELETE) {
rswindell's avatar
rswindell committed
1074
1075
			printf("\nDeleted header.\n");
			smb_freemsgmem(&msg);
rswindell's avatar
rswindell committed
1076
1077
			continue; 
		}
1078
		if(msg.expiration && msg.expiration<=now) {
rswindell's avatar
rswindell committed
1079
1080
			printf("\nExpired message.\n");
			smb_freemsgmem(&msg);
rswindell's avatar
rswindell committed
1081
1082
			continue; 
		}
rswindell's avatar
rswindell committed
1083
1084
1085
1086
1087
1088
		for(m=0;m<datoffsets;m++)
			if(msg.hdr.offset==datoffset[m].old)
				break;
		if(m<datoffsets) {				/* another index pointed to this data */
			printf("duplicate index\n");
			msg.hdr.offset=datoffset[m].new;
1089
			smb_incmsgdat(&smb,datoffset[m].new,smb_getmsgdatlen(&msg),1); 
rswindell's avatar
rswindell committed
1090
		} else {
1091

rswindell's avatar
rswindell committed
1092
1093
1094
1095
1096
1097
1098
			if(!(smb.status.attr&SMB_HYPERALLOC))
				datoffset[datoffsets].old=msg.hdr.offset;

			fseek(smb.sdt_fp,msg.hdr.offset,SEEK_SET);

			m=smb_getmsgdatlen(&msg);
			if(m>16L*1024L*1024L) {
1099
				fprintf(stderr,"\n\7!Invalid data length (%lu)\n",m);
rswindell's avatar
rswindell committed
1100
1101
				continue; 
			}
rswindell's avatar
rswindell committed
1102
1103
1104
1105
1106

			if(!(smb.status.attr&SMB_HYPERALLOC)) {
				datoffset[datoffsets].new=msg.hdr.offset
					=smb_fallocdat(&smb,m,1);
				datoffsets++;
rswindell's avatar
rswindell committed
1107
1108
				fseek(tmp_sdt,msg.hdr.offset,SEEK_SET); 
			}
rswindell's avatar
rswindell committed
1109
1110
			else {
				fseek(tmp_sdt,0L,SEEK_END);
rswindell's avatar
rswindell committed
1111
1112
				msg.hdr.offset=ftell(tmp_sdt); 
			}
rswindell's avatar
rswindell committed
1113
1114
1115
1116
1117
1118
1119
1120
1121

			/* Actually copy the data */

			n=smb_datblocks(m);
			for(m=0;m<n;m++) {
				fread(buf,1,SDT_BLOCK_LEN,smb.sdt_fp);
				if(!m && *(ushort *)buf!=XLAT_NONE && *(ushort *)buf!=XLAT_LZH) {
					printf("\nUnsupported translation type (%04X)\n"
						,*(ushort *)buf);
rswindell's avatar
rswindell committed
1122
1123
1124
1125
					break; 
				}
				fwrite(buf,1,SDT_BLOCK_LEN,tmp_sdt); 
			}
rswindell's avatar
rswindell committed
1126
			if(m<n)