|
|
1.1 root 1: /* smblib.c */
2:
3: /* Synchronet message base (SMB) library routines */
4:
5: /* $Id: smblib.c,v 1.127 2004/12/31 09:38:52 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 library is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details: lgpl.txt or *
18: * http://www.fsf.org/copyleft/lesser.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: /* ANSI C Library headers */
39:
40: #include <time.h>
41: #include <errno.h>
42: #include <fcntl.h>
43: #include <stdio.h>
44: #include <stdlib.h> /* malloc */
45: #include <string.h>
46: #include <ctype.h> /* isdigit */
47: #include <sys/types.h>
48: #include <sys/stat.h> /* must come after sys/types.h */
49:
50: /* SMB-specific headers */
51: #include "smblib.h"
52: #include "genwrap.h"
53: #include "filewrap.h"
54:
55: /* Use smb_ver() and smb_lib_ver() to obtain these values */
56: #define SMBLIB_VERSION "2.40" /* SMB library version */
57: #define SMB_VERSION 0x0121 /* SMB format version */
58: /* High byte major, low byte minor */
59:
60: static char* nulstr="";
61:
62: int SMBCALL smb_ver(void)
63: {
64: return(SMB_VERSION);
65: }
66:
67: char* SMBCALL smb_lib_ver(void)
68: {
69: return(SMBLIB_VERSION);
70: }
71:
72: /****************************************************************************/
73: /* Open a message base of name 'smb->file' */
74: /* Opens files for READing messages or updating message indices only */
75: /****************************************************************************/
76: int SMBCALL smb_open(smb_t* smb)
77: {
78: int i;
79: time_t start=0;
80: smbhdr_t hdr;
81:
82: /* Set default values, if uninitialized */
83: if(!smb->retry_time)
84: smb->retry_time=10; /* seconds */
85: if(!smb->retry_delay
86: || smb->retry_delay>(smb->retry_time*100)) /* at least ten retries */
87: smb->retry_delay=250; /* milliseconds */
88: smb->shd_fp=smb->sdt_fp=smb->sid_fp=NULL;
89: smb->sha_fp=smb->sda_fp=smb->hash_fp=NULL;
90: smb->last_error[0]=0;
91:
92: /* Check for message-base lock semaphore file (under maintenance?) */
93: while(smb_islocked(smb)) {
94: if(!start)
95: start=time(NULL);
96: else
97: if(time(NULL)-start>=(time_t)smb->retry_time)
98: return(SMB_ERR_TIMEOUT);
99: SLEEP(smb->retry_delay);
100: }
101:
102: if((i=smb_open_fp(smb,&smb->shd_fp,SH_DENYNO))!=SMB_SUCCESS)
103: return(i);
104:
105: memset(&(smb->status),0,sizeof(smb->status));
106: if(filelength(fileno(smb->shd_fp))>=(long)sizeof(smbhdr_t)) {
107: setvbuf(smb->shd_fp,NULL,_IONBF,SHD_BLOCK_LEN);
108: if(smb_locksmbhdr(smb)!=SMB_SUCCESS) {
109: smb_close(smb);
110: /* smb_lockmsghdr set last_error */
111: return(SMB_ERR_LOCK);
112: }
113: memset(&hdr,0,sizeof(smbhdr_t));
114: if(smb_fread(smb,&hdr,sizeof(smbhdr_t),smb->shd_fp)!=sizeof(smbhdr_t)) {
115: safe_snprintf(smb->last_error,sizeof(smb->last_error)
116: ,"%d '%s' reading header"
117: ,get_errno(),STRERROR(get_errno()));
118: smb_close(smb);
119: return(SMB_ERR_READ);
120: }
121: if(memcmp(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID)) {
122: safe_snprintf(smb->last_error,sizeof(smb->last_error)
123: ,"corrupt SMB header ID: %.*s"
124: ,LEN_HEADER_ID,hdr.id);
125: smb_close(smb);
126: return(SMB_ERR_HDR_ID);
127: }
128: if(hdr.version<0x110) { /* Compatibility check */
129: safe_snprintf(smb->last_error,sizeof(smb->last_error)
130: ,"insufficient header version: %X"
131: ,hdr.version);
132: smb_close(smb);
133: return(SMB_ERR_HDR_VER);
134: }
135: if(smb_fread(smb,&(smb->status),sizeof(smbstatus_t),smb->shd_fp)!=sizeof(smbstatus_t)) {
136: safe_snprintf(smb->last_error,sizeof(smb->last_error)
137: ,"%d '%s' reading status"
138: ,get_errno(),STRERROR(get_errno()));
139: smb_close(smb);
140: return(SMB_ERR_READ);
141: }
142: if((i=smb_unlocksmbhdr(smb))!=SMB_SUCCESS) {
143: smb_close(smb);
144: return(i);
145: }
146: rewind(smb->shd_fp);
147: }
148:
149: setvbuf(smb->shd_fp,NULL,_IOFBF,SHD_BLOCK_LEN);
150:
151: if((i=smb_open_fp(smb,&smb->sdt_fp,SH_DENYNO))!=SMB_SUCCESS)
152: return(i);
153:
154: if((i=smb_open_fp(smb,&smb->sid_fp,SH_DENYNO))!=SMB_SUCCESS)
155: return(i);
156:
157: return(SMB_SUCCESS);
158: }
159:
160: /****************************************************************************/
161: /* Closes the currently open message base */
162: /****************************************************************************/
163: void SMBCALL smb_close(smb_t* smb)
164: {
165: if(smb->shd_fp!=NULL) {
166: smb_unlocksmbhdr(smb); /* In case it's been locked */
167: smb_close_fp(&smb->shd_fp);
168: }
169: smb_close_fp(&smb->sdt_fp);
170: smb_close_fp(&smb->sid_fp);
171: smb_close_fp(&smb->sda_fp);
172: smb_close_fp(&smb->sha_fp);
173: smb_close_fp(&smb->hash_fp);
174: }
175:
176: /****************************************************************************/
177: /* This set of functions is used to exclusively-lock an entire message base */
178: /* against any other process opening any of the message base files. */
179: /* Currently, this is only used while smbutil packs a message base. */
180: /* This is achieved with a semaphore lock file (e.g. mail.lock). */
181: /****************************************************************************/
182: static char* smb_lockfname(smb_t* smb, char* fname, size_t maxlen)
183: {
184: safe_snprintf(fname,maxlen,"%s.lock",smb->file);
185: return(fname);
186: }
187:
188: /****************************************************************************/
189: /* This function is used to lock an entire message base for exclusive */
190: /* (typically for maintenance/repair) */
191: /****************************************************************************/
192: int SMBCALL smb_lock(smb_t* smb)
193: {
194: char path[MAX_PATH+1];
195: int file;
196: time_t start=0;
197:
198: smb_lockfname(smb,path,sizeof(path)-1);
199: while((file=open(path,O_CREAT|O_EXCL|O_RDWR,S_IREAD|S_IWRITE))==-1) {
200: if(!start)
201: start=time(NULL);
202: else
203: if(time(NULL)-start>=(time_t)smb->retry_time) {
204: safe_snprintf(smb->last_error,sizeof(smb->last_error)
205: ,"%d '%s' creating %s"
206: ,get_errno(),STRERROR(get_errno()),path);
207: return(SMB_ERR_LOCK);
208: }
209: SLEEP(smb->retry_delay);
210: }
211: close(file);
212: return(SMB_SUCCESS);
213: }
214:
215: int SMBCALL smb_unlock(smb_t* smb)
216: {
217: char path[MAX_PATH+1];
218:
219: smb_lockfname(smb,path,sizeof(path)-1);
220: if(remove(path)!=0) {
221: safe_snprintf(smb->last_error,sizeof(smb->last_error)
222: ,"%d '%s' removing %s"
223: ,get_errno(),STRERROR(get_errno()),path);
224: return(SMB_ERR_DELETE);
225: }
226: return(SMB_SUCCESS);
227: }
228:
229: BOOL SMBCALL smb_islocked(smb_t* smb)
230: {
231: char path[MAX_PATH+1];
232:
233: if(access(smb_lockfname(smb,path,sizeof(path)-1),0)!=0)
234: return(FALSE);
235: safe_snprintf(smb->last_error,sizeof(smb->last_error),"%s exists",path);
236: return(TRUE);
237: }
238:
239: /****************************************************************************/
240: /* If the parameter 'push' is non-zero, this function stores the currently */
241: /* open message base to the "virtual" smb stack. Up to SMB_STACK_LEN */
242: /* message bases may be stored (defined in SMBDEFS.H). */
243: /* The parameter 'op' is the operation to perform on the stack. Either */
244: /* SMB_STACK_PUSH, SMB_STACK_POP, or SMB_STACK_XCHNG */
245: /* If the operation is SMB_STACK_POP, this function restores a message base */
246: /* previously saved with a SMB_STACK_PUSH call to this same function. */
247: /* If the operation is SMB_STACK_XCHNG, then the current message base is */
248: /* exchanged with the message base on the top of the stack (most recently */
249: /* pushed. */
250: /* If the current message base is not open, the SMB_STACK_PUSH and */
251: /* SMB_STACK_XCHNG operations do nothing */
252: /* Returns 0 on success, non-zero if stack full. */
253: /* If operation is SMB_STACK_POP or SMB_STACK_XCHNG, it always returns 0. */
254: /****************************************************************************/
255: int SMBCALL smb_stack(smb_t* smb, int op)
256: {
257: static smb_t stack[SMB_STACK_LEN];
258: static int stack_idx;
259: smb_t tmp_smb;
260:
261: if(op==SMB_STACK_PUSH) {
262: if(stack_idx>=SMB_STACK_LEN) {
263: safe_snprintf(smb->last_error,sizeof(smb->last_error),"SMB stack overflow");
264: return(SMB_FAILURE);
265: }
266: if(smb->shd_fp==NULL || smb->sdt_fp==NULL || smb->sid_fp==NULL)
267: return(SMB_SUCCESS); /* Msg base not open, do nothing */
268: memcpy(&stack[stack_idx],smb,sizeof(smb_t));
269: stack_idx++;
270: return(SMB_SUCCESS);
271: }
272: /* pop or xchng */
273: if(!stack_idx) /* Nothing on the stack, so do nothing */
274: return(SMB_SUCCESS);
275: if(op==SMB_STACK_XCHNG) {
276: if(smb->shd_fp==NULL)
277: return(SMB_SUCCESS);
278: memcpy(&tmp_smb,smb,sizeof(smb_t));
279: }
280:
281: stack_idx--;
282: memcpy(smb,&stack[stack_idx],sizeof(smb_t));
283: if(op==SMB_STACK_XCHNG) {
284: memcpy(&stack[stack_idx],&tmp_smb,sizeof(smb_t));
285: stack_idx++;
286: }
287: return(SMB_SUCCESS);
288: }
289:
290: /****************************************************************************/
291: /* Truncates header file */
292: /* Retrys for smb.retry_time number of seconds */
293: /* Return 0 on success, non-zero otherwise */
294: /****************************************************************************/
295: int SMBCALL smb_trunchdr(smb_t* smb)
296: {
297: time_t start=0;
298:
299: if(smb->shd_fp==NULL) {
300: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
301: return(SMB_ERR_NOT_OPEN);
302: }
303: rewind(smb->shd_fp);
304: while(1) {
305: if(chsize(fileno(smb->shd_fp),0L)==0)
306: break;
307: if(get_errno()!=EACCES && get_errno()!=EAGAIN) {
308: safe_snprintf(smb->last_error,sizeof(smb->last_error)
309: ,"%d '%s' changing header file size"
310: ,get_errno(),STRERROR(get_errno()));
311: return(SMB_ERR_WRITE);
312: }
313: if(!start)
314: start=time(NULL);
315: else
316: if(time(NULL)-start>=(time_t)smb->retry_time) { /* Time-out */
317: safe_snprintf(smb->last_error,sizeof(smb->last_error)
318: ,"timeout changing header file size (retry_time=%ld)"
319: ,smb->retry_time);
320: return(SMB_ERR_TIMEOUT);
321: }
322: SLEEP(smb->retry_delay);
323: }
324: return(SMB_SUCCESS);
325: }
326:
327: /*********************************/
328: /* Message Base Header Functions */
329: /*********************************/
330:
331: /****************************************************************************/
332: /* Attempts for smb.retry_time number of seconds to lock the msg base hdr */
333: /****************************************************************************/
334: int SMBCALL smb_locksmbhdr(smb_t* smb)
335: {
336: time_t start=0;
337:
338: if(smb->shd_fp==NULL) {
339: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
340: return(SMB_ERR_NOT_OPEN);
341: }
342: while(1) {
343: if(lock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t))==0) {
344: smb->locked=TRUE;
345: return(SMB_SUCCESS);
346: }
347: if(!start)
348: start=time(NULL);
349: else
350: if(time(NULL)-start>=(time_t)smb->retry_time)
351: break;
352: /* In case we've already locked it */
353: if(unlock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t))==0)
354: smb->locked=FALSE;
355: else {
356: SLEEP(smb->retry_delay);
357: }
358: }
359: safe_snprintf(smb->last_error,sizeof(smb->last_error),"timeout locking header");
360: return(SMB_ERR_TIMEOUT);
361: }
362:
363: /****************************************************************************/
364: /* Read the SMB header from the header file and place into smb.status */
365: /****************************************************************************/
366: int SMBCALL smb_getstatus(smb_t* smb)
367: {
368: int i;
369:
370: if(smb->shd_fp==NULL) {
371: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
372: return(SMB_ERR_NOT_OPEN);
373: }
374: setvbuf(smb->shd_fp,NULL,_IONBF,SHD_BLOCK_LEN);
375: clearerr(smb->shd_fp);
376: if(fseek(smb->shd_fp,sizeof(smbhdr_t),SEEK_SET)) {
377: safe_snprintf(smb->last_error,sizeof(smb->last_error)
378: ,"%d '%s' seeking to %u in header file"
379: ,get_errno(),STRERROR(get_errno()),sizeof(smbhdr_t));
380: return(SMB_ERR_SEEK);
381: }
382: i=smb_fread(smb,&(smb->status),sizeof(smbstatus_t),smb->shd_fp);
383: setvbuf(smb->shd_fp,NULL,_IOFBF,SHD_BLOCK_LEN);
384: if(i==sizeof(smbstatus_t))
385: return(SMB_SUCCESS);
386: safe_snprintf(smb->last_error,sizeof(smb->last_error)
387: ,"%d '%s' reading status",get_errno(),STRERROR(get_errno()));
388: return(SMB_ERR_READ);
389: }
390:
391: /****************************************************************************/
392: /* Writes message base header */
393: /****************************************************************************/
394: int SMBCALL smb_putstatus(smb_t* smb)
395: {
396: int i;
397:
398: if(smb->shd_fp==NULL) {
399: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
400: return(SMB_ERR_NOT_OPEN);
401: }
402: clearerr(smb->shd_fp);
403: if(fseek(smb->shd_fp,sizeof(smbhdr_t),SEEK_SET)) {
404: safe_snprintf(smb->last_error,sizeof(smb->last_error)
405: ,"%d '%s' seeking to %u in header file"
406: ,get_errno(),STRERROR(get_errno()),sizeof(smbhdr_t));
407: return(SMB_ERR_SEEK);
408: }
409: i=fwrite(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
410: fflush(smb->shd_fp);
411: if(i==sizeof(smbstatus_t))
412: return(SMB_SUCCESS);
413: safe_snprintf(smb->last_error,sizeof(smb->last_error)
414: ,"%d '%s' writing status",get_errno(),STRERROR(get_errno()));
415: return(SMB_ERR_WRITE);
416: }
417:
418: /****************************************************************************/
419: /* Unlocks previously locked message base header */
420: /****************************************************************************/
421: int SMBCALL smb_unlocksmbhdr(smb_t* smb)
422: {
423: if(smb->locked) {
424: if(smb->shd_fp==NULL) {
425: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
426: return(SMB_ERR_NOT_OPEN);
427: }
428: if(unlock(fileno(smb->shd_fp),0L,sizeof(smbhdr_t)+sizeof(smbstatus_t))!=0) {
429: safe_snprintf(smb->last_error,sizeof(smb->last_error)
430: ,"%d '%s' unlocking message base header",get_errno(),STRERROR(get_errno()));
431: return(SMB_ERR_UNLOCK);
432: }
433: smb->locked=FALSE;
434: }
435: return(SMB_SUCCESS);
436: }
437:
438: /********************************/
439: /* Individual Message Functions */
440: /********************************/
441:
442: /****************************************************************************/
443: /* Is the offset a valid message header offset? */
444: /****************************************************************************/
445: BOOL SMBCALL smb_valid_hdr_offset(smb_t* smb, ulong offset)
446: {
447: if(offset<sizeof(smbhdr_t)+sizeof(smbstatus_t)
448: || offset<smb->status.header_offset) {
449: safe_snprintf(smb->last_error,sizeof(smb->last_error)
450: ,"invalid header offset: %lu (0x%lX)"
451: ,offset,offset);
452: return(FALSE);
453: }
454: return(TRUE);
455: }
456:
457: /****************************************************************************/
458: /* Attempts for smb.retry_time number of seconds to lock the hdr for 'msg' */
459: /****************************************************************************/
460: int SMBCALL smb_lockmsghdr(smb_t* smb, smbmsg_t* msg)
461: {
462: time_t start=0;
463:
464: if(smb->shd_fp==NULL) {
465: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
466: return(SMB_ERR_NOT_OPEN);
467: }
468: if(!smb_valid_hdr_offset(smb,msg->idx.offset))
469: return(SMB_ERR_HDR_OFFSET);
470:
471: while(1) {
472: if(lock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t))==0)
473: return(SMB_SUCCESS);
474: if(!start)
475: start=time(NULL);
476: else
477: if(time(NULL)-start>=(time_t)smb->retry_time)
478: break;
479: /* In case we've already locked it */
480: if(unlock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t))!=0) {
481: SLEEP(smb->retry_delay);
482: }
483: }
484: safe_snprintf(smb->last_error,sizeof(smb->last_error),"timeout locking header");
485: return(SMB_ERR_TIMEOUT);
486: }
487:
488: /****************************************************************************/
489: /* Fills msg->idx with message index based on msg->hdr.number */
490: /* OR if msg->hdr.number is 0, based on msg->offset (record offset). */
491: /* if msg.hdr.number does not equal 0, then msg->offset is filled too. */
492: /* Either msg->hdr.number or msg->offset must be initialized before */
493: /* calling this function */
494: /* Returns 1 if message number wasn't found, 0 if it was */
495: /****************************************************************************/
496: int SMBCALL smb_getmsgidx(smb_t* smb, smbmsg_t* msg)
497: {
498: idxrec_t idx;
499: ulong byte_offset;
500: ulong l,length,total,bot,top;
501:
502: if(smb->sid_fp==NULL) {
503: safe_snprintf(smb->last_error,sizeof(smb->last_error),"index not open");
504: return(SMB_ERR_NOT_OPEN);
505: }
506: clearerr(smb->sid_fp);
507:
508: length=filelength(fileno(smb->sid_fp));
509: if(length<sizeof(idxrec_t)) {
510: safe_snprintf(smb->last_error,sizeof(smb->last_error)
511: ,"invalid index file length: %ld",length);
512: return(SMB_ERR_FILE_LEN);
513: }
514: total=length/sizeof(idxrec_t);
515: if(!total) {
516: safe_snprintf(smb->last_error,sizeof(smb->last_error)
517: ,"invalid index file length: %ld",length);
518: return(SMB_ERR_FILE_LEN);
519: }
520:
521: if(!msg->hdr.number) {
522: if(msg->offset<0)
523: byte_offset=length-((-msg->offset)*sizeof(idxrec_t));
524: else
525: byte_offset=msg->offset*sizeof(idxrec_t);
526: if(byte_offset>=length) {
527: safe_snprintf(smb->last_error,sizeof(smb->last_error)
528: ,"invalid index offset: %ld, byte offset: %lu, length: %lu"
529: ,msg->offset, byte_offset, length);
530: return(SMB_ERR_HDR_OFFSET);
531: }
532: if(fseek(smb->sid_fp,byte_offset,SEEK_SET)) {
533: safe_snprintf(smb->last_error,sizeof(smb->last_error)
534: ,"%d '%s' seeking to offset %ld (byte %lu) in index file"
535: ,get_errno(),STRERROR(get_errno())
536: ,msg->offset,byte_offset);
537: return(SMB_ERR_SEEK);
538: }
539: if(smb_fread(smb,&msg->idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
540: safe_snprintf(smb->last_error,sizeof(smb->last_error)
541: ,"%d '%s' reading index at offset %ld (byte %lu)"
542: ,get_errno(),STRERROR(get_errno())
543: ,msg->offset,byte_offset);
544: return(SMB_ERR_READ);
545: }
546: return(SMB_SUCCESS);
547: }
548:
549: bot=0;
550: top=total;
551: l=total/2; /* Start at middle index */
552: while(1) {
553: if(l>=total) {
554: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msg %lu not found"
555: ,msg->hdr.number);
556: return(SMB_ERR_NOT_FOUND);
557: }
558: if(fseek(smb->sid_fp,l*sizeof(idxrec_t),SEEK_SET)) {
559: safe_snprintf(smb->last_error,sizeof(smb->last_error)
560: ,"%d '%s' seeking to offset %lu (byte %lu) in index file"
561: ,get_errno(),STRERROR(get_errno())
562: ,l,l*sizeof(idxrec_t));
563: return(SMB_ERR_SEEK);
564: }
565: if(smb_fread(smb,&idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
566: safe_snprintf(smb->last_error,sizeof(smb->last_error)
567: ,"%d '%s' reading index at offset %lu (byte %lu)"
568: ,get_errno(),STRERROR(get_errno()),l,l*sizeof(idxrec_t));
569: return(SMB_ERR_READ);
570: }
571: if(bot==top-1 && idx.number!=msg->hdr.number) {
572: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msg %lu not found"
573: ,msg->hdr.number);
574: return(SMB_ERR_NOT_FOUND);
575: }
576: if(idx.number>msg->hdr.number) {
577: top=l;
578: l=bot+((top-bot)/2);
579: continue;
580: }
581: if(idx.number<msg->hdr.number) {
582: bot=l;
583: l=top-((top-bot)/2);
584: continue;
585: }
586: break;
587: }
588: msg->idx=idx;
589: msg->offset=l;
590: return(SMB_SUCCESS);
591: }
592:
593: /****************************************************************************/
594: /* Reads the first index record in the open message base */
595: /****************************************************************************/
596: int SMBCALL smb_getfirstidx(smb_t* smb, idxrec_t *idx)
597: {
598: if(smb->sid_fp==NULL) {
599: safe_snprintf(smb->last_error,sizeof(smb->last_error),"index not open");
600: return(SMB_ERR_NOT_OPEN);
601: }
602: clearerr(smb->sid_fp);
603: if(fseek(smb->sid_fp,0,SEEK_SET)) {
604: safe_snprintf(smb->last_error,sizeof(smb->last_error)
605: ,"%d '%s' seeking to beginning of index file"
606: ,get_errno(),STRERROR(get_errno()));
607: return(SMB_ERR_SEEK);
608: }
609: if(smb_fread(smb,idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
610: safe_snprintf(smb->last_error,sizeof(smb->last_error)
611: ,"%d '%s' reading first index"
612: ,get_errno(),STRERROR(get_errno()));
613: return(SMB_ERR_READ);
614: }
615: return(SMB_SUCCESS);
616: }
617:
618: /****************************************************************************/
619: /* Reads the last index record in the open message base */
620: /****************************************************************************/
621: int SMBCALL smb_getlastidx(smb_t* smb, idxrec_t *idx)
622: {
623: long length;
624:
625: if(smb->sid_fp==NULL) {
626: safe_snprintf(smb->last_error,sizeof(smb->last_error),"index not open");
627: return(SMB_ERR_NOT_OPEN);
628: }
629: clearerr(smb->sid_fp);
630: length=filelength(fileno(smb->sid_fp));
631: if(length<(long)sizeof(idxrec_t)) {
632: safe_snprintf(smb->last_error,sizeof(smb->last_error)
633: ,"invalid index file length: %ld",length);
634: return(SMB_ERR_FILE_LEN);
635: }
636: if(fseek(smb->sid_fp,length-sizeof(idxrec_t),SEEK_SET)) {
637: safe_snprintf(smb->last_error,sizeof(smb->last_error)
638: ,"%d '%s' seeking to %u in index file"
639: ,get_errno(),STRERROR(get_errno())
640: ,(unsigned)(length-sizeof(idxrec_t)));
641: return(SMB_ERR_SEEK);
642: }
643: if(smb_fread(smb,idx,sizeof(idxrec_t),smb->sid_fp)!=sizeof(idxrec_t)) {
644: safe_snprintf(smb->last_error,sizeof(smb->last_error)
645: ,"%d '%s' reading last index"
646: ,get_errno(),STRERROR(get_errno()));
647: return(SMB_ERR_READ);
648: }
649: return(SMB_SUCCESS);
650: }
651:
652: /****************************************************************************/
653: /* Figures out the total length of the header record for 'msg' */
654: /* Returns length */
655: /****************************************************************************/
656: ulong SMBCALL smb_getmsghdrlen(smbmsg_t* msg)
657: {
658: int i;
659: ulong length;
660:
661: /* fixed portion */
662: length=sizeof(msghdr_t);
663: /* data fields */
664: length+=msg->hdr.total_dfields*sizeof(dfield_t);
665: /* header fields */
666: for(i=0;i<msg->total_hfields;i++) {
667: length+=sizeof(hfield_t);
668: length+=msg->hfield[i].length;
669: }
670: return(length);
671: }
672:
673: /****************************************************************************/
674: /* Figures out the total length of the data buffer for 'msg' */
675: /* Returns length */
676: /****************************************************************************/
677: ulong SMBCALL smb_getmsgdatlen(smbmsg_t* msg)
678: {
679: int i;
680: ulong length=0L;
681:
682: for(i=0;i<msg->hdr.total_dfields;i++)
683: length+=msg->dfield[i].length;
684: return(length);
685: }
686:
687: /****************************************************************************/
688: /* Figures out the total length of the text buffer for 'msg' */
689: /* Returns length */
690: /****************************************************************************/
691: ulong SMBCALL smb_getmsgtxtlen(smbmsg_t* msg)
692: {
693: int i;
694: ulong length=0L;
695:
696: for(i=0;i<msg->total_hfields;i++)
697: if(msg->hfield[i].type==SMB_COMMENT || msg->hfield[i].type==SMTPSYSMSG)
698: length+=msg->hfield[i].length+2;
699: for(i=0;i<msg->hdr.total_dfields;i++)
700: if(msg->dfield[i].type==TEXT_BODY || msg->dfield[i].type==TEXT_TAIL)
701: length+=msg->dfield[i].length;
702: return(length);
703: }
704:
705: static void set_convenience_ptr(smbmsg_t* msg, ushort hfield_type, void* hfield_dat)
706: {
707: switch(hfield_type) { /* convenience variables */
708: case SENDER:
709: if(!msg->from) {
710: msg->from=(char*)hfield_dat;
711: break;
712: }
713: case FORWARDED: /* fall through */
714: msg->forwarded=TRUE;
715: break;
716: case SENDERAGENT:
717: if(!msg->forwarded)
718: msg->from_agent=*(ushort *)hfield_dat;
719: break;
720: case SENDEREXT:
721: if(!msg->forwarded)
722: msg->from_ext=(char*)hfield_dat;
723: break;
724: case SENDERORG:
725: if(!msg->forwarded)
726: msg->from_org=(char*)hfield_dat;
727: break;
728: case SENDERNETTYPE:
729: if(!msg->forwarded)
730: msg->from_net.type=*(ushort *)hfield_dat;
731: break;
732: case SENDERNETADDR:
733: if(!msg->forwarded)
734: msg->from_net.addr=(char*)hfield_dat;
735: break;
736: case REPLYTO:
737: msg->replyto=(char*)hfield_dat;
738: break;
739: case REPLYTOEXT:
740: msg->replyto_ext=(char*)hfield_dat;
741: break;
742: case REPLYTOAGENT:
743: msg->replyto_agent=*(ushort *)hfield_dat;
744: break;
745: case REPLYTONETTYPE:
746: msg->replyto_net.type=*(ushort *)hfield_dat;
747: break;
748: case REPLYTONETADDR:
749: msg->replyto_net.addr=(char*)hfield_dat;
750: break;
751: case RECIPIENT:
752: msg->to=(char*)hfield_dat;
753: break;
754: case RECIPIENTEXT:
755: msg->to_ext=(char*)hfield_dat;
756: break;
757: case RECIPIENTAGENT:
758: msg->to_agent=*(ushort *)hfield_dat;
759: break;
760: case RECIPIENTNETTYPE:
761: msg->to_net.type=*(ushort *)hfield_dat;
762: break;
763: case RECIPIENTNETADDR:
764: msg->to_net.addr=(char*)hfield_dat;
765: break;
766: case SUBJECT:
767: msg->subj=(char*)hfield_dat;
768: break;
769: case SMB_SUMMARY:
770: msg->summary=(char*)hfield_dat;
771: break;
772: case SMB_EXPIRATION:
773: msg->expiration=*(time_t*)hfield_dat;
774: break;
775: case SMB_PRIORITY:
776: msg->priority=*(ulong*)hfield_dat;
777: break;
778: case SMB_COST:
779: msg->cost=*(ulong*)hfield_dat;
780: break;
781: case RFC822MSGID:
782: msg->id=(char*)hfield_dat;
783: break;
784: case RFC822REPLYID:
785: msg->reply_id=(char*)hfield_dat;
786: break;
787: case SMTPREVERSEPATH:
788: msg->reverse_path=(char*)hfield_dat;
789: break;
790: case USENETPATH:
791: msg->path=(char*)hfield_dat;
792: break;
793: case USENETNEWSGROUPS:
794: msg->newsgroups=(char*)hfield_dat;
795: break;
796: case FIDOMSGID:
797: msg->ftn_msgid=(char*)hfield_dat;
798: break;
799: case FIDOREPLYID:
800: msg->ftn_reply=(char*)hfield_dat;
801: break;
802: case FIDOAREA:
803: msg->ftn_area=(char*)hfield_dat;
804: break;
805: case FIDOPID:
806: msg->ftn_pid=(char*)hfield_dat;
807: break;
808: case FIDOTID:
809: msg->ftn_tid=(char*)hfield_dat;
810: break;
811: case FIDOFLAGS:
812: msg->ftn_flags=(char*)hfield_dat;
813: break;
814: }
815: }
816:
817: static void clear_convenience_ptrs(smbmsg_t* msg)
818: {
819: msg->from=NULL;
820: msg->from_ext=NULL;
821: msg->from_org=NULL;
822: memset(&msg->from_net,0,sizeof(net_t));
823:
824: msg->replyto=NULL;
825: msg->replyto_ext=NULL;
826: memset(&msg->replyto_net,0,sizeof(net_t));
827:
828: msg->to=NULL;
829: msg->to_ext=NULL;
830: memset(&msg->to_net,0,sizeof(net_t));
831:
832: msg->subj=NULL;
833: msg->summary=NULL;
834: msg->id=NULL;
835: msg->reply_id=NULL;
836: msg->reverse_path=NULL;
837: msg->path=NULL;
838: msg->newsgroups=NULL;
839:
840: msg->ftn_msgid=NULL;
841: msg->ftn_reply=NULL;
842: msg->ftn_area=NULL;
843: msg->ftn_pid=NULL;
844: msg->ftn_tid=NULL;
845: msg->ftn_flags=NULL;
846: }
847:
848: /****************************************************************************/
849: /* Read header information into 'msg' structure */
850: /* msg->idx.offset must be set before calling this function */
851: /* Must call smb_freemsgmem() to free memory allocated for var len strs */
852: /* Returns 0 on success, non-zero if error */
853: /****************************************************************************/
854: int SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
855: {
856: void *vp,**vpp;
857: ushort i;
858: ulong l,offset;
859: idxrec_t idx;
860:
861: if(smb->shd_fp==NULL) {
862: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
863: return(SMB_ERR_NOT_OPEN);
864: }
865:
866: if(!smb_valid_hdr_offset(smb,msg->idx.offset))
867: return(SMB_ERR_HDR_OFFSET);
868:
869: rewind(smb->shd_fp);
870: if(fseek(smb->shd_fp,msg->idx.offset,SEEK_SET)) {
871: safe_snprintf(smb->last_error,sizeof(smb->last_error)
872: ,"%d '%s' seeking to %lu in header"
873: ,get_errno(),STRERROR(get_errno())
874: ,msg->idx.offset);
875: return(SMB_ERR_SEEK);
876: }
877:
878: idx=msg->idx;
879: offset=msg->offset;
880: memset(msg,0,sizeof(smbmsg_t));
881: msg->idx=idx;
882: msg->offset=offset;
883: if(smb_fread(smb,&msg->hdr,sizeof(msghdr_t),smb->shd_fp)!=sizeof(msghdr_t)) {
884: safe_snprintf(smb->last_error,sizeof(smb->last_error)
885: ,"%d '%s' reading msg header"
886: ,get_errno(),STRERROR(get_errno()));
887: return(SMB_ERR_READ);
888: }
889: if(memcmp(msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID)) {
890: safe_snprintf(smb->last_error,sizeof(smb->last_error)
891: ,"corrupt message header ID: %.*s at offset %lu"
892: ,LEN_HEADER_ID,msg->hdr.id,msg->idx.offset);
893: return(SMB_ERR_HDR_ID);
894: }
895: if(msg->hdr.version<0x110) {
896: safe_snprintf(smb->last_error,sizeof(smb->last_error)
897: ,"insufficient header version: %X"
898: ,msg->hdr.version);
899: return(SMB_ERR_HDR_VER);
900: }
901: l=sizeof(msghdr_t);
902: if(msg->hdr.total_dfields && (msg->dfield
903: =(dfield_t *)MALLOC(sizeof(dfield_t)*msg->hdr.total_dfields))==NULL) {
904: smb_freemsgmem(msg);
905: safe_snprintf(smb->last_error,sizeof(smb->last_error)
906: ,"malloc failure of %d bytes for %d data fields"
907: ,(int)sizeof(dfield_t)*msg->hdr.total_dfields, msg->hdr.total_dfields);
908: return(SMB_ERR_MEM);
909: }
910: i=0;
911: while(i<msg->hdr.total_dfields && l<(ulong)msg->hdr.length) {
912: if(smb_fread(smb,&msg->dfield[i],sizeof(dfield_t),smb->shd_fp)!=sizeof(dfield_t)) {
913: smb_freemsgmem(msg);
914: safe_snprintf(smb->last_error,sizeof(smb->last_error)
915: ,"%d '%s' reading data field %d"
916: ,get_errno(),STRERROR(get_errno()),i);
917: return(SMB_ERR_READ);
918: }
919: i++;
920: l+=sizeof(dfield_t);
921: }
922: if(i<msg->hdr.total_dfields) {
923: smb_freemsgmem(msg);
924: safe_snprintf(smb->last_error,sizeof(smb->last_error)
925: ,"insufficient data fields read (%d instead of %d)"
926: ,i,msg->hdr.total_dfields);
927: return(SMB_ERR_READ);
928: }
929: while(l<(ulong)msg->hdr.length) {
930: i=msg->total_hfields;
931: if((vpp=(void* *)REALLOC(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL) {
932: smb_freemsgmem(msg);
933: safe_snprintf(smb->last_error,sizeof(smb->last_error)
934: ,"realloc failure of %d bytes for header field data"
935: ,(int)sizeof(void*)*(i+1));
936: return(SMB_ERR_MEM);
937: }
938: msg->hfield_dat=vpp;
939: if((vp=(hfield_t *)REALLOC(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL) {
940: smb_freemsgmem(msg);
941: safe_snprintf(smb->last_error,sizeof(smb->last_error)
942: ,"realloc failure of %d bytes for header fields"
943: ,(int)sizeof(hfield_t)*(i+1));
944: return(SMB_ERR_MEM);
945: }
946: msg->hfield=vp;
947: if(smb_fread(smb,&msg->hfield[i],sizeof(hfield_t),smb->shd_fp)!=sizeof(hfield_t)) {
948: smb_freemsgmem(msg);
949: safe_snprintf(smb->last_error,sizeof(smb->last_error)
950: ,"%d '%s' reading header field"
951: ,get_errno(),STRERROR(get_errno()));
952: return(SMB_ERR_READ);
953: }
954: l+=sizeof(hfield_t);
955: if((msg->hfield_dat[i]=(char*)MALLOC(msg->hfield[i].length+1))
956: ==NULL) { /* Allocate 1 extra for ASCIIZ terminator */
957: safe_snprintf(smb->last_error,sizeof(smb->last_error)
958: ,"malloc failure of %d bytes for header field %d"
959: ,msg->hfield[i].length+1, i);
960: smb_freemsgmem(msg); /* or 0 length field */
961: return(SMB_ERR_MEM);
962: }
963: msg->total_hfields++;
964: memset(msg->hfield_dat[i],0,msg->hfield[i].length+1); /* init to NULL */
965: if(msg->hfield[i].length
966: && smb_fread(smb,msg->hfield_dat[i],msg->hfield[i].length,smb->shd_fp)
967: !=(size_t)msg->hfield[i].length) {
968: smb_freemsgmem(msg);
969: safe_snprintf(smb->last_error,sizeof(smb->last_error)
970: ,"%d '%s' reading header field data"
971: ,get_errno(),STRERROR(get_errno()));
972: return(SMB_ERR_READ);
973: }
974: set_convenience_ptr(msg,msg->hfield[i].type,msg->hfield_dat[i]);
975:
976: l+=msg->hfield[i].length;
977: }
978:
979: /* These convenience pointers must point to something */
980: if(msg->from==NULL) msg->from=nulstr;
981: if(msg->to==NULL) msg->to=nulstr;
982: if(msg->subj==NULL) msg->subj=nulstr;
983:
984: /* If no reverse path specified, use sender's address */
985: if(msg->reverse_path == NULL)
986: msg->reverse_path = msg->from_net.addr;
987:
988: return(SMB_SUCCESS);
989: }
990:
991: /****************************************************************************/
992: /* Frees memory allocated for variable-length header fields in 'msg' */
993: /****************************************************************************/
994: void SMBCALL smb_freemsghdrmem(smbmsg_t* msg)
995: {
996: ushort i;
997:
998: for(i=0;i<msg->total_hfields;i++)
999: if(msg->hfield_dat[i]) {
1000: FREE(msg->hfield_dat[i]);
1001: msg->hfield_dat[i]=NULL;
1002: }
1003: msg->total_hfields=0;
1004: if(msg->hfield) {
1005: FREE(msg->hfield);
1006: msg->hfield=NULL;
1007: }
1008: if(msg->hfield_dat) {
1009: FREE(msg->hfield_dat);
1010: msg->hfield_dat=NULL;
1011: }
1012: clear_convenience_ptrs(msg); /* don't leave pointers to freed memory */
1013: }
1014:
1015: /****************************************************************************/
1016: /* Frees memory allocated for 'msg' */
1017: /****************************************************************************/
1018: void SMBCALL smb_freemsgmem(smbmsg_t* msg)
1019: {
1020: if(msg->dfield) {
1021: FREE(msg->dfield);
1022: msg->dfield=NULL;
1023: }
1024: msg->hdr.total_dfields=0;
1025: smb_freemsghdrmem(msg);
1026: }
1027:
1028: /****************************************************************************/
1029: /* Copies memory allocated for 'srcmsg' to 'msg' */
1030: /****************************************************************************/
1031: int SMBCALL smb_copymsgmem(smb_t* smb, smbmsg_t* msg, smbmsg_t* srcmsg)
1032: {
1033: int i;
1034:
1035: memcpy(msg,srcmsg,sizeof(smbmsg_t));
1036:
1037: /* data field types/lengths */
1038: if(msg->hdr.total_dfields>0) {
1039: if((msg->dfield=(dfield_t *)MALLOC(msg->hdr.total_dfields*sizeof(dfield_t)))==NULL) {
1040: if(smb!=NULL)
1041: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1042: ,"malloc failure of %d bytes for %d data fields"
1043: ,msg->hdr.total_dfields*sizeof(dfield_t), msg->hdr.total_dfields);
1044: return(SMB_ERR_MEM);
1045: }
1046: memcpy(msg->dfield,srcmsg->dfield,msg->hdr.total_dfields*sizeof(dfield_t));
1047: }
1048:
1049: /* header field types/lengths */
1050: if(msg->total_hfields>0) {
1051: if((msg->hfield=(hfield_t *)MALLOC(msg->total_hfields*sizeof(hfield_t)))==NULL) {
1052: if(smb!=NULL)
1053: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1054: ,"malloc failure of %d bytes for %d header fields"
1055: ,msg->total_hfields*sizeof(hfield_t), msg->total_hfields);
1056: return(SMB_ERR_MEM);
1057: }
1058: memcpy(msg->hfield,srcmsg->hfield,msg->total_hfields*sizeof(hfield_t));
1059:
1060: /* header field data */
1061: if((msg->hfield_dat=(void**)MALLOC(msg->total_hfields*sizeof(void*)))==NULL) {
1062: if(smb!=NULL)
1063: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1064: ,"malloc failure of %d bytes for %d header fields"
1065: ,msg->total_hfields*sizeof(void*), msg->total_hfields);
1066: return(SMB_ERR_MEM);
1067: }
1068:
1069: for(i=0;i<msg->total_hfields;i++) {
1070: if((msg->hfield_dat[i]=(void*)MALLOC(msg->hfield[i].length+1))==NULL) {
1071: if(smb!=NULL)
1072: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1073: ,"malloc failure of %d bytes for header field #%d"
1074: ,msg->hfield[i].length+1, i+1);
1075: return(SMB_ERR_MEM);
1076: }
1077: memset(msg->hfield_dat[i],0,msg->hfield[i].length+1);
1078: memcpy(msg->hfield_dat[i],srcmsg->hfield_dat[i],msg->hfield[i].length);
1079: }
1080: }
1081:
1082: return(SMB_SUCCESS);
1083: }
1084:
1085: /****************************************************************************/
1086: /* Unlocks header for 'msg' */
1087: /****************************************************************************/
1088: int SMBCALL smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg)
1089: {
1090: if(smb->shd_fp==NULL) {
1091: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
1092: return(SMB_ERR_NOT_OPEN);
1093: }
1094: if(!smb_valid_hdr_offset(smb,msg->idx.offset))
1095: return(SMB_ERR_HDR_OFFSET);
1096: return(unlock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t)));
1097: }
1098:
1099:
1100: /****************************************************************************/
1101: /* Adds a header field to the 'msg' structure (in memory only) */
1102: /****************************************************************************/
1103: int SMBCALL smb_hfield(smbmsg_t* msg, ushort type, size_t length, void* data)
1104: {
1105: void** vpp;
1106: hfield_t* hp;
1107: int i;
1108:
1109: if(smb_getmsghdrlen(msg)+sizeof(hfield_t)+length>SMB_MAX_HDR_LEN)
1110: return(SMB_ERR_HDR_LEN);
1111:
1112: i=msg->total_hfields;
1113: if((hp=(hfield_t *)REALLOC(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL)
1114: return(SMB_ERR_MEM);
1115:
1116: msg->hfield=hp;
1117: if((vpp=(void* *)REALLOC(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL)
1118: return(SMB_ERR_MEM);
1119:
1120: msg->hfield_dat=vpp;
1121: msg->total_hfields++;
1122: msg->hfield[i].type=type;
1123: msg->hfield[i].length=length;
1124: if(length) {
1125: if((msg->hfield_dat[i]=(void* )MALLOC(length+1))==NULL)
1126: return(SMB_ERR_MEM); /* Allocate 1 extra for ASCIIZ terminator */
1127: memset(msg->hfield_dat[i],0,length+1);
1128: memcpy(msg->hfield_dat[i],data,length);
1129: set_convenience_ptr(msg,type,msg->hfield_dat[i]);
1130: }
1131: else
1132: msg->hfield_dat[i]=NULL;
1133:
1134: return(SMB_SUCCESS);
1135: }
1136:
1137: /****************************************************************************/
1138: /* Adds a list of header fields to the 'msg' structure (in memory only) */
1139: /****************************************************************************/
1140: int SMBCALL smb_hfield_addlist(smbmsg_t* msg, hfield_t** hfield_list, void** hfield_dat)
1141: {
1142: int retval;
1143: unsigned n;
1144:
1145: if(hfield_list==NULL)
1146: return(SMB_FAILURE);
1147:
1148: for(n=0;hfield_list[n]!=NULL;n++)
1149: if((retval=smb_hfield(msg
1150: ,hfield_list[n]->type,hfield_list[n]->length,hfield_dat[n]))!=SMB_SUCCESS)
1151: return(retval);
1152:
1153: return(SMB_SUCCESS);
1154: }
1155:
1156: /****************************************************************************/
1157: /* Convenience function to add an ASCIIZ string header field */
1158: /****************************************************************************/
1159: int SMBCALL smb_hfield_str(smbmsg_t* msg, ushort type, const char* str)
1160: {
1161: return smb_hfield(msg, type, strlen(str), (void*)str);
1162: }
1163:
1164: /****************************************************************************/
1165: /* Convenience function to add an ASCIIZ string header field */
1166: /****************************************************************************/
1167: int SMBCALL smb_hfield_netaddr(smbmsg_t* msg, ushort type, const char* str, ushort* nettype)
1168: {
1169: fidoaddr_t sys_addr = {0,0,0,0}; /* replace unspecified fields with 0 (don't assume 1:1/1) */
1170: fidoaddr_t fidoaddr;
1171: ushort tmp_nettype=NET_UNKNOWN;
1172:
1173: if(nettype==NULL)
1174: nettype=&tmp_nettype;
1175: if(*nettype==NET_UNKNOWN)
1176: *nettype=smb_netaddr_type(str);
1177: if(*nettype==NET_FIDO) {
1178: fidoaddr=smb_atofaddr(&sys_addr,str);
1179: return smb_hfield_bin(msg,type,fidoaddr);
1180: } else
1181: return smb_hfield_str(msg,type,str);
1182: }
1183:
1184: /****************************************************************************/
1185: /* Appends data to an existing header field (in memory only) */
1186: /****************************************************************************/
1187: int SMBCALL smb_hfield_append(smbmsg_t* msg, ushort type, size_t length, void* data)
1188: {
1189: int i;
1190: BYTE* p;
1191:
1192: if(length==0) /* nothing to append */
1193: return(SMB_SUCCESS);
1194:
1195: if(msg->total_hfields<1)
1196: return(SMB_ERR_NOT_FOUND);
1197:
1198: /* search for the last header field of this type */
1199: for(i=msg->total_hfields-1;i>=0;i--)
1200: if(msg->hfield[i].type == type)
1201: break;
1202: if(i<0)
1203: return(SMB_ERR_NOT_FOUND);
1204:
1205: if(smb_getmsghdrlen(msg)+length>SMB_MAX_HDR_LEN)
1206: return(SMB_ERR_HDR_LEN);
1207:
1208: if((p=(BYTE*)REALLOC(msg->hfield_dat[i],msg->hfield[i].length+length+1))==NULL)
1209: return(SMB_ERR_MEM); /* Allocate 1 extra for ASCIIZ terminator */
1210:
1211: msg->hfield_dat[i]=p;
1212: p+=msg->hfield[i].length; /* skip existing data */
1213: memset(p,0,length+1);
1214: memcpy(p,data,length); /* append */
1215: msg->hfield[i].length+=length;
1216: set_convenience_ptr(msg,type,msg->hfield_dat[i]);
1217:
1218: return(SMB_SUCCESS);
1219: }
1220:
1221: /****************************************************************************/
1222: /* Appends data to an existing ASCIIZ header field (in memory only) */
1223: /****************************************************************************/
1224: int SMBCALL smb_hfield_append_str(smbmsg_t* msg, ushort type, const char* str)
1225: {
1226: return smb_hfield_append(msg, type, strlen(str), (void*)str);
1227: }
1228:
1229: /****************************************************************************/
1230: /* Searches for a specific header field (by type) and returns it */
1231: /****************************************************************************/
1232: void* SMBCALL smb_get_hfield(smbmsg_t* msg, ushort type, hfield_t* hfield)
1233: {
1234: int i;
1235:
1236: for(i=0;i<msg->total_hfields;i++)
1237: if(msg->hfield[i].type == type) {
1238: if(hfield != NULL)
1239: *hfield = msg->hfield[i];
1240: return(msg->hfield_dat[i]);
1241: }
1242:
1243: return(NULL);
1244: }
1245:
1246: /****************************************************************************/
1247: /* Adds a data field to the 'msg' structure (in memory only) */
1248: /* Automatically figures out the offset into the data buffer from existing */
1249: /* dfield lengths */
1250: /****************************************************************************/
1251: int SMBCALL smb_dfield(smbmsg_t* msg, ushort type, ulong length)
1252: {
1253: dfield_t* dp;
1254: int i,j;
1255:
1256: i=msg->hdr.total_dfields;
1257: if((dp=(dfield_t *)REALLOC(msg->dfield,sizeof(dfield_t)*(i+1)))==NULL)
1258: return(SMB_ERR_MEM);
1259:
1260: msg->dfield=dp;
1261: msg->hdr.total_dfields++;
1262: msg->dfield[i].type=type;
1263: msg->dfield[i].length=length;
1264: for(j=msg->dfield[i].offset=0;j<i;j++)
1265: msg->dfield[i].offset+=msg->dfield[j].length;
1266: return(SMB_SUCCESS);
1267: }
1268:
1269: /****************************************************************************/
1270: /* Checks CRC history file for duplicate crc. If found, returns 1. */
1271: /* If no dupe, adds to CRC history and returns 0, or negative if error. */
1272: /****************************************************************************/
1273: int SMBCALL smb_addcrc(smb_t* smb, ulong crc)
1274: {
1275: char str[MAX_PATH+1];
1276: int file;
1277: int wr;
1278: long length;
1279: long newlen;
1280: ulong l,*buf;
1281: time_t start=0;
1282:
1283: if(!smb->status.max_crcs)
1284: return(SMB_SUCCESS);
1285:
1286: SAFEPRINTF(str,"%s.sch",smb->file);
1287: while(1) {
1288: if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,S_IREAD|S_IWRITE))!=-1)
1289: break;
1290: if(get_errno()!=EACCES && get_errno()!=EAGAIN) {
1291: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1292: ,"%d '%s' opening %s"
1293: ,get_errno(),STRERROR(get_errno()),str);
1294: return(SMB_ERR_OPEN);
1295: }
1296: if(!start)
1297: start=time(NULL);
1298: else
1299: if(time(NULL)-start>=(time_t)smb->retry_time) {
1300: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1301: ,"timeout opening %s (retry_time=%ld)"
1302: ,str,smb->retry_time);
1303: return(SMB_ERR_TIMEOUT);
1304: }
1305: SLEEP(smb->retry_delay);
1306: }
1307:
1308: length=filelength(file);
1309: if(length<0L || length%sizeof(long)) {
1310: close(file);
1311: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1312: ,"invalid file length: %ld", length);
1313: return(SMB_ERR_FILE_LEN);
1314: }
1315:
1316: if(length!=0) {
1317: if((buf=(ulong*)MALLOC(length))==NULL) {
1318: close(file);
1319: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1320: ,"malloc failure of %ld bytes"
1321: ,length);
1322: return(SMB_ERR_MEM);
1323: }
1324:
1325: if(read(file,buf,length)!=length) {
1326: close(file);
1327: FREE(buf);
1328: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1329: ,"%d '%s' reading %ld bytes"
1330: ,get_errno(),STRERROR(get_errno()),length);
1331: return(SMB_ERR_READ);
1332: }
1333:
1334: for(l=0;l<length/sizeof(long);l++)
1335: if(crc==buf[l])
1336: break;
1337: if(l<length/sizeof(long)) { /* Dupe CRC found */
1338: close(file);
1339: FREE(buf);
1340: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1341: ,"duplicate message text CRC detected");
1342: return(SMB_DUPE_MSG);
1343: }
1344:
1345: if(length>=(long)(smb->status.max_crcs*sizeof(long))) {
1346: newlen=(smb->status.max_crcs-1)*sizeof(long);
1347: chsize(file,0); /* truncate it */
1348: lseek(file,0L,SEEK_SET);
1349: write(file,buf+(length-newlen),newlen);
1350: }
1351: FREE(buf);
1352: }
1353: wr=write(file,&crc,sizeof(crc)); /* Write to the end */
1354: close(file);
1355:
1356: if(wr!=sizeof(crc)) {
1357: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1358: ,"%d '%s' writing %u bytes"
1359: ,get_errno(),STRERROR(get_errno()),sizeof(crc));
1360: return(SMB_ERR_WRITE);
1361: }
1362:
1363: return(SMB_SUCCESS);
1364: }
1365:
1366: /****************************************************************************/
1367: /* Creates a new message header record in the header file. */
1368: /* If storage is SMB_SELFPACK, self-packing conservative allocation is used */
1369: /* If storage is SMB_FASTALLOC, fast allocation is used */
1370: /* If storage is SMB_HYPERALLOC, no allocation tables are used (fastest) */
1371: /* This function will UN-lock the SMB header */
1372: /****************************************************************************/
1373: int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
1374: {
1375: int i;
1376: long l;
1377: ulong hdrlen;
1378:
1379: if(smb->shd_fp==NULL) {
1380: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
1381: return(SMB_ERR_NOT_OPEN);
1382: }
1383:
1384: if(!smb->locked && smb_locksmbhdr(smb)!=SMB_SUCCESS)
1385: return(SMB_ERR_LOCK);
1386:
1387: hdrlen=smb_getmsghdrlen(msg);
1388: if(hdrlen>SMB_MAX_HDR_LEN) { /* headers are limited to 64k in size */
1389: smb_unlocksmbhdr(smb);
1390: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1391: ,"illegal message header length (%lu > %u)"
1392: ,hdrlen,SMB_MAX_HDR_LEN);
1393: return(SMB_ERR_HDR_LEN);
1394: }
1395:
1396: if((i=smb_getstatus(smb))!=SMB_SUCCESS) {
1397: smb_unlocksmbhdr(smb);
1398: return(i);
1399: }
1400: msg->idx.number=msg->hdr.number=smb->status.last_msg+1;
1401:
1402: /* This is *not* a dupe-check */
1403: if(!(msg->flags&MSG_FLAG_HASHED) /* not already hashed */
1404: && (i=smb_hashmsg(smb,msg,NULL,/* update? */TRUE))!=SMB_SUCCESS) {
1405: smb_unlocksmbhdr(smb);
1406: return(i); /* error updating hash table */
1407: }
1408:
1409: if(storage!=SMB_HYPERALLOC && (i=smb_open_ha(smb))!=SMB_SUCCESS) {
1410: smb_unlocksmbhdr(smb);
1411: return(i);
1412: }
1413:
1414: if(msg->hdr.version==0)
1415: msg->hdr.version=SMB_VERSION;
1416: msg->hdr.length=(ushort)hdrlen;
1417: if(storage==SMB_HYPERALLOC)
1418: l=smb_hallochdr(smb);
1419: else if(storage==SMB_FASTALLOC)
1420: l=smb_fallochdr(smb,msg->hdr.length);
1421: else
1422: l=smb_allochdr(smb,msg->hdr.length);
1423: if(storage!=SMB_HYPERALLOC)
1424: smb_close_ha(smb);
1425: if(l<0) {
1426: smb_unlocksmbhdr(smb);
1427: return(l);
1428: }
1429:
1430: msg->idx.offset=smb->status.header_offset+l;
1431: msg->idx.time=msg->hdr.when_imported.time;
1432: msg->idx.attr=msg->hdr.attr;
1433: msg->offset=smb->status.total_msgs;
1434: i=smb_putmsg(smb,msg);
1435: if(i==SMB_SUCCESS) {
1436: smb->status.last_msg++;
1437: smb->status.total_msgs++;
1438: smb_putstatus(smb);
1439: }
1440: smb_unlocksmbhdr(smb);
1441: return(i);
1442: }
1443:
1444:
1445: /****************************************************************************/
1446: /* Writes both header and index information for msg 'msg' */
1447: /****************************************************************************/
1448: int SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg)
1449: {
1450: int i;
1451:
1452: i=smb_putmsghdr(smb,msg);
1453: if(i)
1454: return(i);
1455: return(smb_putmsgidx(smb,msg));
1456: }
1457:
1458: /****************************************************************************/
1459: /* Writes index information for 'msg' */
1460: /* msg->idx */
1461: /* and msg->offset must be set prior to calling to this function */
1462: /* Returns 0 if everything ok */
1463: /****************************************************************************/
1464: int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
1465: {
1466: if(smb->sid_fp==NULL) {
1467: safe_snprintf(smb->last_error,sizeof(smb->last_error),"index not open");
1468: return(SMB_ERR_NOT_OPEN);
1469: }
1470: clearerr(smb->sid_fp);
1471: if(fseek(smb->sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET)) {
1472: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1473: ,"%d '%s' seeking to %u in header"
1474: ,get_errno(),STRERROR(get_errno())
1475: ,(unsigned)(msg->offset*sizeof(idxrec_t)));
1476: return(SMB_ERR_SEEK);
1477: }
1478: if(!fwrite(&msg->idx,sizeof(idxrec_t),1,smb->sid_fp)) {
1479: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1480: ,"%d '%s' writing index"
1481: ,get_errno(),STRERROR(get_errno()));
1482: return(SMB_ERR_WRITE);
1483: }
1484: fflush(smb->sid_fp);
1485: return(SMB_SUCCESS);
1486: }
1487:
1488: /****************************************************************************/
1489: /* Writes header information for 'msg' */
1490: /* msg->hdr.length */
1491: /* msg->idx.offset */
1492: /* and msg->offset must be set prior to calling to this function */
1493: /* Returns 0 if everything ok */
1494: /****************************************************************************/
1495: int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
1496: {
1497: ushort i;
1498: ulong hdrlen;
1499:
1500: if(smb->shd_fp==NULL) {
1501: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
1502: return(SMB_ERR_NOT_OPEN);
1503: }
1504:
1505: if(!smb_valid_hdr_offset(smb,msg->idx.offset))
1506: return(SMB_ERR_HDR_OFFSET);
1507:
1508: clearerr(smb->shd_fp);
1509: if(fseek(smb->shd_fp,msg->idx.offset,SEEK_SET)) {
1510: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1511: ,"%d '%s' seeking to %lu in index"
1512: ,get_errno(),STRERROR(get_errno()),msg->idx.offset);
1513: return(SMB_ERR_SEEK);
1514: }
1515: /* Verify that the number of blocks required to stored the actual
1516: (calculated) header length does not exceed the number allocated. */
1517: hdrlen=smb_getmsghdrlen(msg);
1518: if(hdrlen>SMB_MAX_HDR_LEN) { /* headers are limited to 64k in size */
1519: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1520: ,"illegal message header length (%lu > %u)"
1521: ,hdrlen,SMB_MAX_HDR_LEN);
1522: return(SMB_ERR_HDR_LEN);
1523: }
1524: if(smb_hdrblocks(hdrlen) > smb_hdrblocks(msg->hdr.length)) {
1525: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1526: ,"illegal header length increase: %lu (%lu blocks) vs %hu (%lu blocks)"
1527: ,hdrlen, smb_hdrblocks(hdrlen)
1528: ,msg->hdr.length, smb_hdrblocks(msg->hdr.length));
1529: return(SMB_ERR_HDR_LEN);
1530: }
1531: msg->hdr.length=(ushort)hdrlen; /* store the actual header length */
1532: /**********************************/
1533: /* Set the message header ID here */
1534: /**********************************/
1535: memcpy(&msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID);
1536:
1537: /************************************************/
1538: /* Write the fixed portion of the header record */
1539: /************************************************/
1540: if(!fwrite(&msg->hdr,sizeof(msghdr_t),1,smb->shd_fp)) {
1541: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1542: ,"%d '%s' writing fixed portion of header record"
1543: ,get_errno(),STRERROR(get_errno()));
1544: return(SMB_ERR_WRITE);
1545: }
1546:
1547: /************************************************/
1548: /* Write the data fields (each is fixed length) */
1549: /************************************************/
1550: for(i=0;i<msg->hdr.total_dfields;i++)
1551: if(!fwrite(&msg->dfield[i],sizeof(dfield_t),1,smb->shd_fp)) {
1552: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1553: ,"%d '%s' writing data field"
1554: ,get_errno(),STRERROR(get_errno()));
1555: return(SMB_ERR_WRITE);
1556: }
1557: /*******************************************/
1558: /* Write the variable length header fields */
1559: /*******************************************/
1560: for(i=0;i<msg->total_hfields;i++) {
1561: if(!fwrite(&msg->hfield[i],sizeof(hfield_t),1,smb->shd_fp)) {
1562: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1563: ,"%d '%s' writing header field"
1564: ,get_errno(),STRERROR(get_errno()));
1565: return(SMB_ERR_WRITE);
1566: }
1567: if(msg->hfield[i].length /* more then 0 bytes long */
1568: && !fwrite(msg->hfield_dat[i],msg->hfield[i].length,1,smb->shd_fp)) {
1569: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1570: ,"%d '%s' writing header field data"
1571: ,get_errno(),STRERROR(get_errno()));
1572: return(SMB_ERR_WRITE);
1573: }
1574: }
1575:
1576: while(hdrlen%SHD_BLOCK_LEN) {
1577: if(fputc(0,smb->shd_fp)!=0) {
1578: safe_snprintf(smb->last_error,sizeof(smb->last_error)
1579: ,"%d '%s' padding header block"
1580: ,get_errno(),STRERROR(get_errno()));
1581: return(SMB_ERR_WRITE); /* pad block with NULL */
1582: }
1583: hdrlen++;
1584: }
1585: fflush(smb->shd_fp);
1586: return(SMB_SUCCESS);
1587: }
1588:
1589: /****************************************************************************/
1590: /* Creates a sub-board's initial header file */
1591: /* Truncates and deletes other associated SMB files */
1592: /****************************************************************************/
1593: int SMBCALL smb_create(smb_t* smb)
1594: {
1595: char str[MAX_PATH+1];
1596: smbhdr_t hdr;
1597:
1598: if(smb->shd_fp==NULL || smb->sdt_fp==NULL || smb->sid_fp==NULL) {
1599: safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
1600: return(SMB_ERR_NOT_OPEN);
1601: }
1602: if(filelength(fileno(smb->shd_fp))>=(long)(sizeof(smbhdr_t)+sizeof(smbstatus_t))
1603: && smb_locksmbhdr(smb)!=SMB_SUCCESS) /* header exists, so lock it */
1604: return(SMB_ERR_LOCK);
1605: memset(&hdr,0,sizeof(smbhdr_t));
1606: memcpy(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID);
1607: hdr.version=SMB_VERSION;
1608: hdr.length=sizeof(smbhdr_t)+sizeof(smbstatus_t);
1609: smb->status.last_msg=smb->status.total_msgs=0;
1610: smb->status.header_offset=sizeof(smbhdr_t)+sizeof(smbstatus_t);
1611: rewind(smb->shd_fp);
1612: fwrite(&hdr,1,sizeof(smbhdr_t),smb->shd_fp);
1613: fwrite(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
1614: rewind(smb->shd_fp);
1615: chsize(fileno(smb->shd_fp),sizeof(smbhdr_t)+sizeof(smbstatus_t));
1616: fflush(smb->shd_fp);
1617:
1618: rewind(smb->sdt_fp);
1619: chsize(fileno(smb->sdt_fp),0L);
1620: rewind(smb->sid_fp);
1621: chsize(fileno(smb->sid_fp),0L);
1622:
1623: SAFEPRINTF(str,"%s.sda",smb->file);
1624: remove(str); /* if it exists, delete it */
1625: SAFEPRINTF(str,"%s.sha",smb->file);
1626: remove(str); /* if it exists, delete it */
1627: SAFEPRINTF(str,"%s.sch",smb->file);
1628: remove(str);
1629: SAFEPRINTF(str,"%s.hash",smb->file);
1630: remove(str);
1631: smb_unlocksmbhdr(smb);
1632: return(SMB_SUCCESS);
1633: }
1634:
1635: /****************************************************************************/
1636: /* Returns number of data blocks required to store "length" amount of data */
1637: /****************************************************************************/
1638: ulong SMBCALL smb_datblocks(ulong length)
1639: {
1640: ulong blocks;
1641:
1642: blocks=length/SDT_BLOCK_LEN;
1643: if(length%SDT_BLOCK_LEN)
1644: blocks++;
1645: return(blocks);
1646: }
1647:
1648: /****************************************************************************/
1649: /* Returns number of header blocks required to store "length" size header */
1650: /****************************************************************************/
1651: ulong SMBCALL smb_hdrblocks(ulong length)
1652: {
1653: ulong blocks;
1654:
1655: blocks=length/SHD_BLOCK_LEN;
1656: if(length%SHD_BLOCK_LEN)
1657: blocks++;
1658: return(blocks);
1659: }
1660:
1661: /****************************************************************************/
1662: /* Returns difference from specified timezone and UTC/GMT */
1663: /****************************************************************************/
1664: int SMBCALL smb_tzutc(short zone)
1665: {
1666: int tz;
1667:
1668: if(OTHER_ZONE(zone))
1669: return(zone);
1670:
1671: tz=zone&0xfff;
1672: if(zone&(WESTERN_ZONE|US_ZONE)) /* West of UTC? */
1673: return(-tz);
1674: return(tz);
1675: }
1676:
1677: /****************************************************************************/
1678: /****************************************************************************/
1679: int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum)
1680: {
1681: int retval=SMB_ERR_NOT_FOUND;
1682: ulong nextmsgnum;
1683: smbmsg_t nextmsg;
1684:
1685: if(!remsg->hdr.thread_first) { /* New msg is first reply */
1686: remsg->hdr.thread_first=newmsgnum;
1687: if((retval=smb_lockmsghdr(smb,remsg))!=SMB_SUCCESS)
1688: return(retval);
1689: retval=smb_putmsghdr(smb,remsg);
1690: smb_unlockmsghdr(smb,remsg);
1691: return(retval);
1692: }
1693:
1694: /* Search for last reply and extend chain */
1695: memset(&nextmsg,0,sizeof(nextmsg));
1696: nextmsgnum=remsg->hdr.thread_first; /* start with first reply */
1697:
1698: while(1) {
1699: nextmsg.idx.offset=0;
1700: nextmsg.hdr.number=nextmsgnum;
1701: if(smb_getmsgidx(smb, &nextmsg)!=SMB_SUCCESS) /* invalid thread origin */
1702: break;
1703: if(smb_lockmsghdr(smb,&nextmsg)!=SMB_SUCCESS)
1704: break;
1705: if(smb_getmsghdr(smb, &nextmsg)!=SMB_SUCCESS) {
1706: smb_unlockmsghdr(smb,&nextmsg);
1707: break;
1708: }
1709: if(nextmsg.hdr.thread_next && nextmsg.hdr.thread_next!=nextmsgnum) {
1710: nextmsgnum=nextmsg.hdr.thread_next;
1711: smb_unlockmsghdr(smb,&nextmsg);
1712: smb_freemsgmem(&nextmsg);
1713: continue;
1714: }
1715: nextmsg.hdr.thread_next=newmsgnum;
1716: retval=smb_putmsghdr(smb,&nextmsg);
1717: smb_unlockmsghdr(smb,&nextmsg);
1718: smb_freemsgmem(&nextmsg);
1719: break;
1720: }
1721:
1722: return(retval);
1723: }
1724:
1725: /* End of SMBLIB.C */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.