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