Annotation of sbbs/src/smblib/smblib.c, revision 1.1.1.1

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 */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.