Annotation of sbbs/src/smblib/smblib.c, revision 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.