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

1.1       root        1: /* smblib.c */
                      2: 
                      3: /* Synchronet message base (SMB) library routines */
                      4: 
1.1.1.2 ! root        5: /* $Id: smblib.c,v 1.147 2011/07/21 19:05:18 rswindell Exp $ */
1.1       root        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:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       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 */
1.1.1.2 ! root       56: #define SMBLIB_VERSION         "2.51"      /* SMB library version */
1.1       root       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 */
1.1.1.2 ! root      706:                case AUTHOR:
        !           707:                        msg->from=(char*)hfield_dat;
        !           708:                        break; 
1.1       root      709:                case SENDER:
1.1.1.2 ! root      710:                        if(msg->from==NULL || *(msg->from)==0) {
1.1       root      711:                                msg->from=(char*)hfield_dat;
                    712:                                break; 
                    713:                        }
                    714:                case FORWARDED:         /* fall through */
                    715:                        msg->forwarded=TRUE;
                    716:                        break;
                    717:                case SENDERAGENT:
                    718:                        if(!msg->forwarded)
                    719:                                msg->from_agent=*(ushort *)hfield_dat;
                    720:                        break;
                    721:                case SENDEREXT:
                    722:                        if(!msg->forwarded)
                    723:                                msg->from_ext=(char*)hfield_dat;
                    724:                        break;
                    725:                case SENDERORG:
                    726:                        if(!msg->forwarded)
                    727:                                msg->from_org=(char*)hfield_dat;
                    728:                        break;
                    729:                case SENDERNETTYPE:
                    730:                        if(!msg->forwarded)
                    731:                                msg->from_net.type=*(ushort *)hfield_dat;
                    732:                        break;
                    733:                case SENDERNETADDR:
                    734:                        if(!msg->forwarded)
                    735:                                msg->from_net.addr=(char*)hfield_dat;
                    736:                        break;
1.1.1.2 ! root      737:                case SENDERIPADDR:
        !           738:                        msg->from_ip=(char*)hfield_dat;
        !           739:                        break;
        !           740:                case SENDERHOSTNAME:
        !           741:                        msg->from_host=(char*)hfield_dat;
        !           742:                        break;
        !           743:                case SENDERPROTOCOL:
        !           744:                        msg->from_prot=(char*)hfield_dat;
        !           745:                        break;
1.1       root      746:                case REPLYTO:
                    747:                        msg->replyto=(char*)hfield_dat;
                    748:                        break;
                    749:                case REPLYTOEXT:
                    750:                        msg->replyto_ext=(char*)hfield_dat;
                    751:                        break;
                    752:                case REPLYTOAGENT:
                    753:                        msg->replyto_agent=*(ushort *)hfield_dat;
                    754:                        break;
                    755:                case REPLYTONETTYPE:
                    756:                        msg->replyto_net.type=*(ushort *)hfield_dat;
                    757:                        break;
                    758:                case REPLYTONETADDR:
                    759:                        msg->replyto_net.addr=(char*)hfield_dat;
                    760:                        break;
                    761:                case RECIPIENT:
                    762:                        msg->to=(char*)hfield_dat;
                    763:                        break;
                    764:                case RECIPIENTEXT:
                    765:                        msg->to_ext=(char*)hfield_dat;
                    766:                        break;
                    767:                case RECIPIENTAGENT:
                    768:                        msg->to_agent=*(ushort *)hfield_dat;
                    769:                        break;
                    770:                case RECIPIENTNETTYPE:
                    771:                        msg->to_net.type=*(ushort *)hfield_dat;
                    772:                        break;
                    773:                case RECIPIENTNETADDR:
                    774:                        msg->to_net.addr=(char*)hfield_dat;
                    775:                        break;
                    776:                case SUBJECT:
                    777:                        msg->subj=(char*)hfield_dat;
                    778:                        break;
                    779:                case SMB_SUMMARY:
                    780:                        msg->summary=(char*)hfield_dat;
                    781:                        break;
                    782:                case SMB_EXPIRATION:
1.1.1.2 ! root      783:                        msg->expiration=*(uint32_t*)hfield_dat;
1.1       root      784:                        break;
                    785:                case SMB_PRIORITY:
1.1.1.2 ! root      786:                        msg->priority=*(uint32_t*)hfield_dat;
1.1       root      787:                        break;
                    788:                case SMB_COST:
1.1.1.2 ! root      789:                        msg->cost=*(uint32_t*)hfield_dat;
1.1       root      790:                        break;
                    791:                case RFC822MSGID:
                    792:                        msg->id=(char*)hfield_dat;
                    793:                        break;
                    794:                case RFC822REPLYID:
                    795:                        msg->reply_id=(char*)hfield_dat;
                    796:                        break;
                    797:                case SMTPREVERSEPATH:
                    798:                        msg->reverse_path=(char*)hfield_dat;
                    799:                        break;
                    800:                case USENETPATH:
                    801:                        msg->path=(char*)hfield_dat;
                    802:                        break;
                    803:                case USENETNEWSGROUPS:
                    804:                        msg->newsgroups=(char*)hfield_dat;
                    805:                        break;
                    806:                case FIDOMSGID:
                    807:                        msg->ftn_msgid=(char*)hfield_dat;
                    808:                        break;
                    809:                case FIDOREPLYID:
                    810:                        msg->ftn_reply=(char*)hfield_dat;
                    811:                        break;
                    812:                case FIDOAREA:
                    813:                        msg->ftn_area=(char*)hfield_dat;
                    814:                        break;
                    815:                case FIDOPID:
                    816:                        msg->ftn_pid=(char*)hfield_dat;
                    817:                        break;
                    818:                case FIDOTID:
                    819:                        msg->ftn_tid=(char*)hfield_dat;
                    820:                        break;
                    821:                case FIDOFLAGS:
                    822:                        msg->ftn_flags=(char*)hfield_dat;
                    823:                        break;
                    824:        }
                    825: }
                    826: 
                    827: static void clear_convenience_ptrs(smbmsg_t* msg)
                    828: {
                    829:        msg->from=NULL;
                    830:        msg->from_ext=NULL;
                    831:        msg->from_org=NULL;
1.1.1.2 ! root      832:        msg->from_ip=NULL;
        !           833:        msg->from_host=NULL;
        !           834:        msg->from_prot=NULL;
1.1       root      835:        memset(&msg->from_net,0,sizeof(net_t));
                    836: 
                    837:        msg->replyto=NULL;
                    838:        msg->replyto_ext=NULL;
                    839:        memset(&msg->replyto_net,0,sizeof(net_t));
                    840: 
                    841:        msg->to=NULL;
                    842:        msg->to_ext=NULL;
                    843:        memset(&msg->to_net,0,sizeof(net_t));
                    844: 
                    845:        msg->subj=NULL;
                    846:        msg->summary=NULL;
                    847:        msg->id=NULL;
                    848:        msg->reply_id=NULL;
                    849:        msg->reverse_path=NULL;
                    850:        msg->path=NULL;
                    851:        msg->newsgroups=NULL;
                    852: 
                    853:        msg->ftn_msgid=NULL;
                    854:        msg->ftn_reply=NULL;
                    855:        msg->ftn_area=NULL;
                    856:        msg->ftn_pid=NULL;
                    857:        msg->ftn_tid=NULL;
                    858:        msg->ftn_flags=NULL;
                    859: }
                    860: 
                    861: /****************************************************************************/
                    862: /* Read header information into 'msg' structure                             */
                    863: /* msg->idx.offset must be set before calling this function                            */
                    864: /* Must call smb_freemsgmem() to free memory allocated for var len strs        */
                    865: /* Returns 0 on success, non-zero if error                                                                     */
                    866: /****************************************************************************/
                    867: int SMBCALL smb_getmsghdr(smb_t* smb, smbmsg_t* msg)
                    868: {
                    869:        void    *vp,**vpp;
                    870:        ushort  i;
                    871:        ulong   l,offset;
                    872:        idxrec_t idx;
                    873: 
                    874:        if(smb->shd_fp==NULL) {
                    875:                safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
                    876:                return(SMB_ERR_NOT_OPEN);
                    877:        }
                    878: 
                    879:        if(!smb_valid_hdr_offset(smb,msg->idx.offset))
                    880:                return(SMB_ERR_HDR_OFFSET);
                    881: 
                    882:        rewind(smb->shd_fp);
                    883:        if(fseek(smb->shd_fp,msg->idx.offset,SEEK_SET)) {
                    884:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    885:                        ,"%d '%s' seeking to %lu in header"
                    886:                        ,get_errno(),STRERROR(get_errno())
                    887:                        ,msg->idx.offset);
                    888:                return(SMB_ERR_SEEK);
                    889:        }
                    890: 
                    891:        idx=msg->idx;
                    892:        offset=msg->offset;
                    893:        memset(msg,0,sizeof(smbmsg_t));
                    894:        msg->idx=idx;
                    895:        msg->offset=offset;
                    896:        if(smb_fread(smb,&msg->hdr,sizeof(msghdr_t),smb->shd_fp)!=sizeof(msghdr_t)) {
                    897:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    898:                        ,"%d '%s' reading msg header"
                    899:                        ,get_errno(),STRERROR(get_errno()));
                    900:                return(SMB_ERR_READ);
                    901:        }
                    902:        if(memcmp(msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID)) {
                    903:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    904:                        ,"corrupt message header ID: %.*s at offset %lu"
                    905:                        ,LEN_HEADER_ID,msg->hdr.id,msg->idx.offset);
                    906:                return(SMB_ERR_HDR_ID);
                    907:        }
                    908:        if(msg->hdr.version<0x110) {
                    909:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    910:                        ,"insufficient header version: %X"
                    911:                        ,msg->hdr.version);
                    912:                return(SMB_ERR_HDR_VER);
                    913:        }
                    914:        l=sizeof(msghdr_t);
                    915:        if(msg->hdr.total_dfields && (msg->dfield
                    916:                =(dfield_t *)malloc(sizeof(dfield_t)*msg->hdr.total_dfields))==NULL) {
                    917:                smb_freemsgmem(msg);
                    918:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    919:                        ,"malloc failure of %d bytes for %d data fields"
                    920:                        ,(int)sizeof(dfield_t)*msg->hdr.total_dfields, msg->hdr.total_dfields);
                    921:                return(SMB_ERR_MEM); 
                    922:        }
                    923:        i=0;
                    924:        while(i<msg->hdr.total_dfields && l<(ulong)msg->hdr.length) {
                    925:                if(smb_fread(smb,&msg->dfield[i],sizeof(dfield_t),smb->shd_fp)!=sizeof(dfield_t)) {
                    926:                        smb_freemsgmem(msg);
                    927:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    928:                                ,"%d '%s' reading data field %d"
                    929:                                ,get_errno(),STRERROR(get_errno()),i);
                    930:                        return(SMB_ERR_READ); 
                    931:                }
                    932:                i++;
                    933:                l+=sizeof(dfield_t); 
                    934:        }
                    935:        if(i<msg->hdr.total_dfields) {
                    936:                smb_freemsgmem(msg);
                    937:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    938:                        ,"insufficient data fields read (%d instead of %d)"
                    939:                        ,i,msg->hdr.total_dfields);
                    940:                return(SMB_ERR_READ); 
                    941:        }
                    942:        while(l<(ulong)msg->hdr.length) {
                    943:                i=msg->total_hfields;
                    944:                if((vpp=(void* *)realloc(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL) {
                    945:                        smb_freemsgmem(msg);
                    946:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    947:                                ,"realloc failure of %d bytes for header field data"
                    948:                                ,(int)sizeof(void*)*(i+1));
                    949:                        return(SMB_ERR_MEM); 
                    950:                }
                    951:                msg->hfield_dat=vpp;
                    952:                if((vp=(hfield_t *)realloc(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL) {
                    953:                        smb_freemsgmem(msg);
                    954:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    955:                                ,"realloc failure of %d bytes for header fields"
                    956:                                ,(int)sizeof(hfield_t)*(i+1));
                    957:                        return(SMB_ERR_MEM); 
                    958:                }
                    959:                msg->hfield=vp;
                    960:                if(smb_fread(smb,&msg->hfield[i],sizeof(hfield_t),smb->shd_fp)!=sizeof(hfield_t)) {
                    961:                        smb_freemsgmem(msg);
                    962:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    963:                                ,"%d '%s' reading header field"
                    964:                                ,get_errno(),STRERROR(get_errno()));
                    965:                        return(SMB_ERR_READ); 
                    966:                }
                    967:                l+=sizeof(hfield_t);
                    968:                if((msg->hfield_dat[i]=(char*)malloc(msg->hfield[i].length+1))
                    969:                        ==NULL) {                       /* Allocate 1 extra for ASCIIZ terminator */
                    970:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    971:                                ,"malloc failure of %d bytes for header field %d"
                    972:                                ,msg->hfield[i].length+1, i);
                    973:                        smb_freemsgmem(msg);  /* or 0 length field */
                    974:                        return(SMB_ERR_MEM); 
                    975:                }
                    976:                msg->total_hfields++;
                    977:                memset(msg->hfield_dat[i],0,msg->hfield[i].length+1);  /* init to NULL */
                    978:                if(msg->hfield[i].length
                    979:                        && smb_fread(smb,msg->hfield_dat[i],msg->hfield[i].length,smb->shd_fp)
                    980:                                !=(size_t)msg->hfield[i].length) {
                    981:                        smb_freemsgmem(msg);
                    982:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    983:                                ,"%d '%s' reading header field data"
                    984:                                ,get_errno(),STRERROR(get_errno()));
                    985:                        return(SMB_ERR_READ); 
                    986:                }
                    987:                set_convenience_ptr(msg,msg->hfield[i].type,msg->hfield_dat[i]);
                    988: 
                    989:                l+=msg->hfield[i].length; 
                    990:        }
                    991: 
                    992:        /* These convenience pointers must point to something */
                    993:        if(msg->from==NULL)     msg->from=nulstr;
                    994:        if(msg->to==NULL)       msg->to=nulstr;
                    995:        if(msg->subj==NULL)     msg->subj=nulstr;
                    996: 
                    997:        /* If no reverse path specified, use sender's address */
                    998:        if(msg->reverse_path == NULL && msg->from_net.type==NET_INTERNET)
                    999:                msg->reverse_path = msg->from_net.addr;
                   1000: 
                   1001:        return(SMB_SUCCESS);
                   1002: }
                   1003: 
                   1004: /****************************************************************************/
                   1005: /* Frees memory allocated for variable-length header fields in 'msg'        */
                   1006: /****************************************************************************/
                   1007: void SMBCALL smb_freemsghdrmem(smbmsg_t* msg)
                   1008: {
                   1009:        ushort  i;
                   1010: 
                   1011:        for(i=0;i<msg->total_hfields;i++)
                   1012:                if(msg->hfield_dat[i]) {
                   1013:                        free(msg->hfield_dat[i]);
                   1014:                        msg->hfield_dat[i]=NULL;
                   1015:                }
                   1016:        msg->total_hfields=0;
                   1017:        if(msg->hfield) {
                   1018:                free(msg->hfield);
                   1019:                msg->hfield=NULL;
                   1020:        }
                   1021:        if(msg->hfield_dat) {
                   1022:                free(msg->hfield_dat);
                   1023:                msg->hfield_dat=NULL;
                   1024:        }
                   1025:        clear_convenience_ptrs(msg);    /* don't leave pointers to freed memory */
                   1026: }
                   1027: 
                   1028: /****************************************************************************/
                   1029: /* Frees memory allocated for 'msg'                                         */
                   1030: /****************************************************************************/
                   1031: void SMBCALL smb_freemsgmem(smbmsg_t* msg)
                   1032: {
                   1033:        if(msg->dfield) {
                   1034:                free(msg->dfield);
                   1035:                msg->dfield=NULL;
                   1036:        }
                   1037:        msg->hdr.total_dfields=0;
                   1038:        smb_freemsghdrmem(msg);
                   1039: }
                   1040: 
                   1041: /****************************************************************************/
                   1042: /* Copies memory allocated for 'srcmsg' to 'msg'                                                       */
                   1043: /****************************************************************************/
                   1044: int SMBCALL smb_copymsgmem(smb_t* smb, smbmsg_t* msg, smbmsg_t* srcmsg)
                   1045: {
                   1046:        int i;
                   1047: 
                   1048:        memcpy(msg,srcmsg,sizeof(smbmsg_t));
                   1049: 
                   1050:        /* data field types/lengths */
                   1051:        if(msg->hdr.total_dfields>0) {
                   1052:                if((msg->dfield=(dfield_t *)malloc(msg->hdr.total_dfields*sizeof(dfield_t)))==NULL) {
                   1053:                        if(smb!=NULL)
                   1054:                                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1055:                                        ,"malloc failure of %d bytes for %d data fields"
                   1056:                                        ,msg->hdr.total_dfields*sizeof(dfield_t), msg->hdr.total_dfields);
                   1057:                        return(SMB_ERR_MEM);
                   1058:                }
                   1059:                memcpy(msg->dfield,srcmsg->dfield,msg->hdr.total_dfields*sizeof(dfield_t));
                   1060:        }
                   1061: 
                   1062:        /* header field types/lengths */
                   1063:        if(msg->total_hfields>0) {
                   1064:                if((msg->hfield=(hfield_t *)malloc(msg->total_hfields*sizeof(hfield_t)))==NULL) {
                   1065:                        if(smb!=NULL)
                   1066:                                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1067:                                        ,"malloc failure of %d bytes for %d header fields"
                   1068:                                        ,msg->total_hfields*sizeof(hfield_t), msg->total_hfields);
                   1069:                        return(SMB_ERR_MEM);
                   1070:                }
                   1071:                memcpy(msg->hfield,srcmsg->hfield,msg->total_hfields*sizeof(hfield_t));
                   1072: 
                   1073:                /* header field data */
                   1074:                if((msg->hfield_dat=(void**)malloc(msg->total_hfields*sizeof(void*)))==NULL) {
                   1075:                        if(smb!=NULL)
                   1076:                                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1077:                                        ,"malloc failure of %d bytes for %d header fields"
                   1078:                                        ,msg->total_hfields*sizeof(void*), msg->total_hfields);
                   1079:                        return(SMB_ERR_MEM);
                   1080:                }
                   1081: 
                   1082:                for(i=0;i<msg->total_hfields;i++) {
                   1083:                        if((msg->hfield_dat[i]=(void*)malloc(msg->hfield[i].length+1))==NULL) {
                   1084:                                if(smb!=NULL)
                   1085:                                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1086:                                                ,"malloc failure of %d bytes for header field #%d"
                   1087:                                                ,msg->hfield[i].length+1, i+1);
                   1088:                                return(SMB_ERR_MEM);
                   1089:                        }
                   1090:                        memset(msg->hfield_dat[i],0,msg->hfield[i].length+1);
                   1091:                        memcpy(msg->hfield_dat[i],srcmsg->hfield_dat[i],msg->hfield[i].length);
                   1092:                }
                   1093:        }
                   1094: 
                   1095:        return(SMB_SUCCESS);
                   1096: }
                   1097: 
                   1098: /****************************************************************************/
                   1099: /* Unlocks header for 'msg'                                                 */
                   1100: /****************************************************************************/
                   1101: int SMBCALL smb_unlockmsghdr(smb_t* smb, smbmsg_t* msg)
                   1102: {
                   1103:        if(smb->shd_fp==NULL) {
                   1104:                safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
                   1105:                return(SMB_ERR_NOT_OPEN);
                   1106:        }
                   1107:        if(!smb_valid_hdr_offset(smb,msg->idx.offset))
                   1108:                return(SMB_ERR_HDR_OFFSET);
                   1109:        return(unlock(fileno(smb->shd_fp),msg->idx.offset,sizeof(msghdr_t)));
                   1110: }
                   1111: 
                   1112: 
                   1113: /****************************************************************************/
                   1114: /* Adds a header field to the 'msg' structure (in memory only)              */
                   1115: /****************************************************************************/
1.1.1.2 ! root     1116: int SMBCALL smb_hfield_add(smbmsg_t* msg, ushort type, size_t length, void* data, BOOL insert)
1.1       root     1117: {
                   1118:        void**          vpp;
                   1119:        hfield_t*       hp;
                   1120:        int i;
                   1121: 
                   1122:        if(smb_getmsghdrlen(msg)+sizeof(hfield_t)+length>SMB_MAX_HDR_LEN)
                   1123:                return(SMB_ERR_HDR_LEN);
                   1124: 
                   1125:        i=msg->total_hfields;
                   1126:        if((hp=(hfield_t *)realloc(msg->hfield,sizeof(hfield_t)*(i+1)))==NULL) 
                   1127:                return(SMB_ERR_MEM);
                   1128:        msg->hfield=hp;
1.1.1.2 ! root     1129: 
1.1       root     1130:        if((vpp=(void* *)realloc(msg->hfield_dat,sizeof(void* )*(i+1)))==NULL) 
                   1131:                return(SMB_ERR_MEM);
                   1132:        msg->hfield_dat=vpp;
1.1.1.2 ! root     1133: 
        !          1134:        if(insert) {
        !          1135:                memmove(msg->hfield+1, msg->hfield, sizeof(hfield_t)*i);
        !          1136:                memmove(msg->hfield_dat+1, msg->hfield_dat, sizeof(void*)*i);
        !          1137:                i=0;
        !          1138:        }
1.1       root     1139:        msg->total_hfields++;
                   1140:        msg->hfield[i].type=type;
                   1141:        msg->hfield[i].length=length;
                   1142:        if(length) {
                   1143:                if((msg->hfield_dat[i]=(void* )malloc(length+1))==NULL) 
                   1144:                        return(SMB_ERR_MEM);    /* Allocate 1 extra for ASCIIZ terminator */
                   1145:                memset(msg->hfield_dat[i],0,length+1);
                   1146:                memcpy(msg->hfield_dat[i],data,length); 
                   1147:                set_convenience_ptr(msg,type,msg->hfield_dat[i]);
                   1148:        }
                   1149:        else
                   1150:                msg->hfield_dat[i]=NULL;
                   1151: 
                   1152:        return(SMB_SUCCESS);
                   1153: }
                   1154: 
                   1155: /****************************************************************************/
                   1156: /* Adds a list of header fields to the 'msg' structure (in memory only)     */
                   1157: /****************************************************************************/
1.1.1.2 ! root     1158: int    SMBCALL smb_hfield_add_list(smbmsg_t* msg, hfield_t** hfield_list, void** hfield_dat, BOOL insert)
1.1       root     1159: {
                   1160:        int                     retval;
                   1161:        unsigned        n;
                   1162: 
                   1163:        if(hfield_list==NULL)
                   1164:                return(SMB_FAILURE);
                   1165: 
                   1166:        for(n=0;hfield_list[n]!=NULL;n++)
1.1.1.2 ! root     1167:                if((retval=smb_hfield_add(msg
        !          1168:                        ,hfield_list[n]->type,hfield_list[n]->length,hfield_dat[n],insert))!=SMB_SUCCESS)
1.1       root     1169:                        return(retval);
                   1170: 
                   1171:        return(SMB_SUCCESS);
                   1172: }
                   1173: 
                   1174: /****************************************************************************/
                   1175: /* Convenience function to add an ASCIIZ string header field                           */
                   1176: /****************************************************************************/
1.1.1.2 ! root     1177: int SMBCALL smb_hfield_add_str(smbmsg_t* msg, ushort type, const char* str, BOOL insert)
1.1       root     1178: {
1.1.1.2 ! root     1179:        return smb_hfield_add(msg, type, str==NULL ? 0:strlen(str), (void*)str, insert);
1.1       root     1180: }
                   1181: 
                   1182: /****************************************************************************/
                   1183: /* Convenience function to add an ASCIIZ string header field                           */
                   1184: /****************************************************************************/
1.1.1.2 ! root     1185: int    SMBCALL smb_hfield_add_netaddr(smbmsg_t* msg, ushort type, const char* str, ushort* nettype, BOOL insert)
1.1       root     1186: {
                   1187:        fidoaddr_t      sys_addr = {0,0,0,0};   /* replace unspecified fields with 0 (don't assume 1:1/1) */
                   1188:        fidoaddr_t      fidoaddr;
                   1189:        ushort          tmp_nettype=NET_UNKNOWN;
                   1190: 
                   1191:        if(nettype==NULL)
                   1192:                nettype=&tmp_nettype;
                   1193:        if(*nettype==NET_UNKNOWN)
                   1194:                *nettype=smb_netaddr_type(str);
                   1195:        if(*nettype==NET_FIDO) {
                   1196:                fidoaddr=smb_atofaddr(&sys_addr,str);
1.1.1.2 ! root     1197:                return smb_hfield_add(msg,type,sizeof(fidoaddr),&fidoaddr,insert);
1.1       root     1198:        } else
1.1.1.2 ! root     1199:                return smb_hfield_add_str(msg,type,str,insert);
1.1       root     1200: }
                   1201: 
                   1202: /****************************************************************************/
                   1203: /* Appends data to an existing header field (in memory only)                           */
                   1204: /****************************************************************************/
                   1205: int SMBCALL smb_hfield_append(smbmsg_t* msg, ushort type, size_t length, void* data)
                   1206: {
                   1207:        int             i;
                   1208:        BYTE*   p;
                   1209: 
                   1210:        if(length==0)   /* nothing to append */
                   1211:                return(SMB_SUCCESS);
                   1212: 
                   1213:        if(msg->total_hfields<1)
                   1214:                return(SMB_ERR_NOT_FOUND);
                   1215: 
                   1216:        /* search for the last header field of this type */
                   1217:        for(i=msg->total_hfields-1;i>=0;i--)
                   1218:                if(msg->hfield[i].type == type)
                   1219:                        break;
                   1220:        if(i<0)
                   1221:                return(SMB_ERR_NOT_FOUND);
                   1222: 
                   1223:        if(smb_getmsghdrlen(msg)+length>SMB_MAX_HDR_LEN)
                   1224:                return(SMB_ERR_HDR_LEN);
                   1225: 
                   1226:        if((p=(BYTE*)realloc(msg->hfield_dat[i],msg->hfield[i].length+length+1))==NULL) 
                   1227:                return(SMB_ERR_MEM);    /* Allocate 1 extra for ASCIIZ terminator */
                   1228: 
                   1229:        msg->hfield_dat[i]=p;
                   1230:        p+=msg->hfield[i].length;       /* skip existing data */
                   1231:        memset(p,0,length+1);
                   1232:        memcpy(p,data,length);          /* append */
                   1233:        msg->hfield[i].length+=length;
                   1234:        set_convenience_ptr(msg,type,msg->hfield_dat[i]);
                   1235: 
                   1236:        return(SMB_SUCCESS);
                   1237: }
                   1238: 
                   1239: /****************************************************************************/
                   1240: /* Appends data to an existing ASCIIZ header field (in memory only)                    */
                   1241: /****************************************************************************/
                   1242: int SMBCALL smb_hfield_append_str(smbmsg_t* msg, ushort type, const char* str)
                   1243: {
1.1.1.2 ! root     1244:        return smb_hfield_append(msg, type, str==NULL ? 0:strlen(str), (void*)str);
        !          1245: }
        !          1246: 
        !          1247: /****************************************************************************/
        !          1248: /* Replaces an header field value (in memory only)                                                     */
        !          1249: /****************************************************************************/
        !          1250: int SMBCALL smb_hfield_replace(smbmsg_t* msg, ushort type, size_t length, void* data)
        !          1251: {
        !          1252:        int             i;
        !          1253:        void*   p;
        !          1254: 
        !          1255:        if(msg->total_hfields<1)
        !          1256:                return(SMB_ERR_NOT_FOUND);
        !          1257: 
        !          1258:        /* search for the last header field of this type */
        !          1259:        for(i=msg->total_hfields-1;i>=0;i--)
        !          1260:                if(msg->hfield[i].type == type)
        !          1261:                        break;
        !          1262:        if(i<0)
        !          1263:                return(SMB_ERR_NOT_FOUND);
        !          1264: 
        !          1265:        if((p=(BYTE*)realloc(msg->hfield_dat[i],length+1))==NULL) 
        !          1266:                return(SMB_ERR_MEM);    /* Allocate 1 extra for ASCIIZ terminator */
        !          1267: 
        !          1268:        msg->hfield_dat[i]=p;
        !          1269:        memset(p,0,length+1);
        !          1270:        memcpy(p,data,length);
        !          1271:        msg->hfield[i].length=length;
        !          1272:        set_convenience_ptr(msg,type,msg->hfield_dat[i]);
        !          1273: 
        !          1274:        return SMB_SUCCESS;
        !          1275: }
        !          1276: 
        !          1277: /****************************************************************************/
        !          1278: /* Replace an existing ASCIIZ header field value (in memory only)                      */
        !          1279: /****************************************************************************/
        !          1280: int SMBCALL smb_hfield_replace_str(smbmsg_t* msg, ushort type, const char* str)
        !          1281: {
        !          1282:        return smb_hfield_replace(msg, type, str==NULL ? 0:strlen(str), (void*)str);
1.1       root     1283: }
                   1284: 
                   1285: /****************************************************************************/
                   1286: /* Searches for a specific header field (by type) and returns it                       */
                   1287: /****************************************************************************/
                   1288: void* SMBCALL smb_get_hfield(smbmsg_t* msg, ushort type, hfield_t* hfield)
                   1289: {
                   1290:        int i;
                   1291: 
                   1292:        for(i=0;i<msg->total_hfields;i++)
                   1293:                if(msg->hfield[i].type == type) {
                   1294:                        if(hfield != NULL)
                   1295:                                *hfield = msg->hfield[i];
                   1296:                        return(msg->hfield_dat[i]);
                   1297:                }
                   1298: 
                   1299:        return(NULL);
                   1300: }
                   1301: 
                   1302: /****************************************************************************/
                   1303: /* Adds a data field to the 'msg' structure (in memory only)                */
                   1304: /* Automatically figures out the offset into the data buffer from existing     */
                   1305: /* dfield lengths                                                                                                                      */
                   1306: /****************************************************************************/
                   1307: int SMBCALL smb_dfield(smbmsg_t* msg, ushort type, ulong length)
                   1308: {
                   1309:        dfield_t* dp;
                   1310:        int i,j;
                   1311: 
                   1312:        i=msg->hdr.total_dfields;
                   1313:        if((dp=(dfield_t *)realloc(msg->dfield,sizeof(dfield_t)*(i+1)))==NULL) 
                   1314:                return(SMB_ERR_MEM);
                   1315:        
                   1316:        msg->dfield=dp;
                   1317:        msg->hdr.total_dfields++;
                   1318:        msg->dfield[i].type=type;
                   1319:        msg->dfield[i].length=length;
                   1320:        for(j=msg->dfield[i].offset=0;j<i;j++)
                   1321:                msg->dfield[i].offset+=msg->dfield[j].length;
                   1322:        return(SMB_SUCCESS);
                   1323: }
                   1324: 
                   1325: /****************************************************************************/
                   1326: /* Checks CRC history file for duplicate crc. If found, returns 1.                     */
                   1327: /* If no dupe, adds to CRC history and returns 0, or negative if error.        */
                   1328: /****************************************************************************/
1.1.1.2 ! root     1329: int SMBCALL smb_addcrc(smb_t* smb, uint32_t crc)
1.1       root     1330: {
                   1331:        char    str[MAX_PATH+1];
                   1332:        int     file;
                   1333:        int             wr;
                   1334:        long    length;
                   1335:        long    newlen;
1.1.1.2 ! root     1336:        ulong   l;
        !          1337:        uint32_t *buf;
1.1       root     1338:        time_t  start=0;
                   1339: 
                   1340:        if(!smb->status.max_crcs)
                   1341:                return(SMB_SUCCESS);
                   1342: 
                   1343:        SAFEPRINTF(str,"%s.sch",smb->file);
                   1344:        while(1) {
                   1345:                if((file=sopen(str,O_RDWR|O_CREAT|O_BINARY,SH_DENYRW,S_IREAD|S_IWRITE))!=-1)
                   1346:                        break;
                   1347:                if(get_errno()!=EACCES && get_errno()!=EAGAIN) {
                   1348:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1349:                                ,"%d '%s' opening %s"
                   1350:                                ,get_errno(),STRERROR(get_errno()),str);
                   1351:                        return(SMB_ERR_OPEN);
                   1352:                }
                   1353:                if(!start)
                   1354:                        start=time(NULL);
                   1355:                else
                   1356:                        if(time(NULL)-start>=(time_t)smb->retry_time) {
                   1357:                                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1358:                                        ,"timeout opening %s (retry_time=%ld)"
                   1359:                                        ,str,smb->retry_time);
                   1360:                                return(SMB_ERR_TIMEOUT); 
                   1361:                        }
                   1362:                SLEEP(smb->retry_delay);
                   1363:        }
                   1364: 
                   1365:        length=filelength(file);
1.1.1.2 ! root     1366:        if(length<0L || length%sizeof(uint32_t)) {
1.1       root     1367:                close(file);
                   1368:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1369:                        ,"invalid file length: %ld", length);
                   1370:                return(SMB_ERR_FILE_LEN); 
                   1371:        }
                   1372: 
                   1373:        if(length!=0) {
1.1.1.2 ! root     1374:                if((buf=(uint32_t*)malloc(length))==NULL) {
1.1       root     1375:                        close(file);
                   1376:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1377:                                ,"malloc failure of %ld bytes"
                   1378:                                ,length);
                   1379:                        return(SMB_ERR_MEM); 
                   1380:                }
                   1381: 
                   1382:                if(read(file,buf,length)!=length) {
                   1383:                        close(file);
                   1384:                        free(buf);
                   1385:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1386:                                ,"%d '%s' reading %ld bytes"
                   1387:                                ,get_errno(),STRERROR(get_errno()),length);
                   1388:                        return(SMB_ERR_READ);
                   1389:                }
                   1390: 
1.1.1.2 ! root     1391:                for(l=0;l<length/sizeof(int32_t);l++)
1.1       root     1392:                        if(crc==buf[l])
                   1393:                                break;
1.1.1.2 ! root     1394:                if(l<length/sizeof(int32_t)) {                                  /* Dupe CRC found */
1.1       root     1395:                        close(file);
                   1396:                        free(buf);
                   1397:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1398:                                ,"duplicate message text CRC detected");
                   1399:                        return(SMB_DUPE_MSG);
                   1400:                } 
                   1401: 
1.1.1.2 ! root     1402:                if(length>=(long)(smb->status.max_crcs*sizeof(int32_t))) {
        !          1403:                        newlen=(smb->status.max_crcs-1)*sizeof(int32_t);
1.1       root     1404:                        chsize(file,0); /* truncate it */
                   1405:                        lseek(file,0L,SEEK_SET);
                   1406:                        write(file,buf+(length-newlen),newlen); 
                   1407:                }
                   1408:                free(buf);
                   1409:        }
                   1410:        wr=write(file,&crc,sizeof(crc));        /* Write to the end */
                   1411:        close(file);
                   1412: 
                   1413:        if(wr!=sizeof(crc)) {   
                   1414:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1415:                        ,"%d '%s' writing %u bytes"
                   1416:                        ,get_errno(),STRERROR(get_errno()),sizeof(crc));
                   1417:                return(SMB_ERR_WRITE);
                   1418:        }
                   1419: 
                   1420:        return(SMB_SUCCESS);
                   1421: }
                   1422: 
                   1423: /****************************************************************************/
                   1424: /* Creates a new message header record in the header file.                                     */
                   1425: /* If storage is SMB_SELFPACK, self-packing conservative allocation is used */
                   1426: /* If storage is SMB_FASTALLOC, fast allocation is used                                        */
                   1427: /* If storage is SMB_HYPERALLOC, no allocation tables are used (fastest)       */
                   1428: /* This function will UN-lock the SMB header                                                           */
                   1429: /****************************************************************************/
                   1430: int SMBCALL smb_addmsghdr(smb_t* smb, smbmsg_t* msg, int storage)
                   1431: {
                   1432:        int             i;
                   1433:        long    l;
                   1434:        ulong   hdrlen;
                   1435: 
                   1436:        if(smb->shd_fp==NULL) {
                   1437:                safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
                   1438:                return(SMB_ERR_NOT_OPEN);
                   1439:        }
                   1440: 
                   1441:        if(!smb->locked && smb_locksmbhdr(smb)!=SMB_SUCCESS)
                   1442:                return(SMB_ERR_LOCK);
                   1443: 
                   1444:        hdrlen=smb_getmsghdrlen(msg);
                   1445:        if(hdrlen>SMB_MAX_HDR_LEN) { /* headers are limited to 64k in size */
                   1446:                smb_unlocksmbhdr(smb);
                   1447:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1448:                        ,"illegal message header length (%lu > %u)"
                   1449:                        ,hdrlen,SMB_MAX_HDR_LEN);
                   1450:                return(SMB_ERR_HDR_LEN);
                   1451:        }
                   1452: 
                   1453:        if((i=smb_getstatus(smb))!=SMB_SUCCESS) {
                   1454:                smb_unlocksmbhdr(smb);
                   1455:                return(i);
                   1456:        }
                   1457:        msg->hdr.number=smb->status.last_msg+1;
                   1458: 
                   1459:        /* This is *not* a dupe-check */
                   1460:        if(!(msg->flags&MSG_FLAG_HASHED) /* not already hashed */
1.1.1.2 ! root     1461:                && (i=smb_hashmsg(smb,msg,/* text: */NULL,/* update? */TRUE))!=SMB_SUCCESS) {
1.1       root     1462:                smb_unlocksmbhdr(smb);
                   1463:                return(i);      /* error updating hash table */
                   1464:        }
                   1465: 
                   1466:        if(storage!=SMB_HYPERALLOC && (i=smb_open_ha(smb))!=SMB_SUCCESS) {
                   1467:                smb_unlocksmbhdr(smb);
                   1468:                return(i);
                   1469:        }
                   1470: 
                   1471:        if(msg->hdr.version==0)
                   1472:                msg->hdr.version=SMB_VERSION;
                   1473:        msg->hdr.length=(ushort)hdrlen;
                   1474:        if(storage==SMB_HYPERALLOC)
                   1475:                l=smb_hallochdr(smb);
                   1476:        else if(storage==SMB_FASTALLOC)
                   1477:                l=smb_fallochdr(smb,msg->hdr.length);
                   1478:        else
                   1479:                l=smb_allochdr(smb,msg->hdr.length);
                   1480:        if(storage!=SMB_HYPERALLOC)
                   1481:                smb_close_ha(smb);
                   1482:        if(l<0) {
                   1483:                smb_unlocksmbhdr(smb);
                   1484:                return(l); 
                   1485:        }
                   1486: 
                   1487:        msg->idx.offset=smb->status.header_offset+l;
                   1488:        msg->offset=smb->status.total_msgs;
                   1489:        i=smb_putmsg(smb,msg);
                   1490:        if(i==SMB_SUCCESS) {
                   1491:                smb->status.last_msg++;
                   1492:                smb->status.total_msgs++;
                   1493:                smb_putstatus(smb);
                   1494:        }
                   1495:        smb_unlocksmbhdr(smb);
                   1496:        return(i);
                   1497: }
                   1498: 
                   1499: /****************************************************************************/
                   1500: /* Safely updates existing index and header records for msg                                    */
                   1501: /* Nothing should be locked prior to calling this function and nothing         */
                   1502: /* should (normally) be locked when it exits                                                           */
                   1503: /****************************************************************************/
                   1504: int SMBCALL smb_updatemsg(smb_t* smb, smbmsg_t* msg)
                   1505: {
                   1506:        int retval;
                   1507: 
                   1508:        /* Insure no one else can be changing the index at this time */
                   1509:        if((retval=smb_locksmbhdr(smb))!=SMB_SUCCESS)
                   1510:                return(retval);
                   1511:        /* Get the current index record offset (for later update by smb_putmsgidx) */
                   1512:        if((retval=smb_getmsgidx(smb, msg))==SMB_SUCCESS) {
                   1513:                /* Don't let any one else read or write this header while we're updating it */
                   1514:                if((retval=smb_lockmsghdr(smb,msg))==SMB_SUCCESS) {
                   1515:                        retval=smb_putmsg(smb,msg);
                   1516:                        smb_unlockmsghdr(smb,msg);
                   1517:                }
                   1518:        }
                   1519:        smb_unlocksmbhdr(smb);
                   1520:        return(retval);
                   1521: }
                   1522: 
                   1523: /****************************************************************************/
                   1524: /* Writes both header and index information for msg 'msg'                   */
                   1525: /****************************************************************************/
                   1526: int SMBCALL smb_putmsg(smb_t* smb, smbmsg_t* msg)
                   1527: {
                   1528:        int i;
                   1529: 
                   1530:        smb_init_idx(smb,msg);
                   1531: 
                   1532:        if((i=smb_putmsghdr(smb,msg))!=SMB_SUCCESS)
                   1533:                return(i);
                   1534: 
                   1535:        return(smb_putmsgidx(smb,msg));
                   1536: }
                   1537: 
                   1538: /****************************************************************************/
                   1539: /* Initializes/re-synchronizes all the fields of the message index record      */
                   1540: /* with the values from the message header (except for the header offset)      */
                   1541: /****************************************************************************/
                   1542: int SMBCALL smb_init_idx(smb_t* smb, smbmsg_t* msg)
                   1543: {
                   1544:        msg->idx.subj=smb_subject_crc(msg->subj);
                   1545: 
                   1546:        if(smb->status.attr&SMB_EMAIL) {
                   1547:                if(msg->to_ext)
                   1548:                        msg->idx.to=atoi(msg->to_ext);
                   1549:                else
                   1550:                        msg->idx.to=0;
                   1551:                if(msg->from_ext)
                   1552:                        msg->idx.from=atoi(msg->from_ext);
                   1553:                else
                   1554:                        msg->idx.from=0; 
                   1555:        } else {
                   1556:                msg->idx.to=smb_name_crc(msg->to);
                   1557:                msg->idx.from=smb_name_crc(msg->from);
                   1558:        }
                   1559: 
                   1560:        /* Make sure these index/header fields are always *nsync */
                   1561:        msg->idx.number = msg->hdr.number;
                   1562:        msg->idx.attr   = msg->hdr.attr;        
                   1563:        msg->idx.time   = msg->hdr.when_imported.time;
                   1564: 
                   1565:        return(SMB_SUCCESS);
                   1566: }
                   1567: 
                   1568: /****************************************************************************/
                   1569: /* Writes index information for 'msg'                                       */
                   1570: /* msg->idx                                                                                                                            */
                   1571: /* and msg->offset must be set prior to calling to this function                       */
                   1572: /* Returns 0 if everything ok                                               */
                   1573: /****************************************************************************/
                   1574: int SMBCALL smb_putmsgidx(smb_t* smb, smbmsg_t* msg)
                   1575: {
                   1576:        long length;
                   1577: 
                   1578:        if(smb->sid_fp==NULL) {
                   1579:                safe_snprintf(smb->last_error,sizeof(smb->last_error),"index not open");
                   1580:                return(SMB_ERR_NOT_OPEN);
                   1581:        }
                   1582:        clearerr(smb->sid_fp);
                   1583:        length = filelength(fileno(smb->sid_fp));
                   1584:        if(length < (long)(msg->offset*sizeof(idxrec_t))) {
                   1585:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1586:                        ,"invalid index offset: %ld, byte offset: %lu, length: %lu"
                   1587:                        ,msg->offset, msg->offset*sizeof(idxrec_t), length);
                   1588:                return(SMB_ERR_HDR_OFFSET);
                   1589:        }
                   1590:        if(fseek(smb->sid_fp,msg->offset*sizeof(idxrec_t),SEEK_SET)) {
                   1591:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1592:                        ,"%d '%s' seeking to %u in header"
                   1593:                        ,get_errno(),STRERROR(get_errno())
                   1594:                        ,(unsigned)(msg->offset*sizeof(idxrec_t)));
                   1595:                return(SMB_ERR_SEEK);
                   1596:        }
                   1597:        if(!fwrite(&msg->idx,sizeof(idxrec_t),1,smb->sid_fp)) {
                   1598:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1599:                        ,"%d '%s' writing index"
                   1600:                        ,get_errno(),STRERROR(get_errno()));
                   1601:                return(SMB_ERR_WRITE);
                   1602:        }
                   1603:        return fflush(smb->sid_fp);     /* SMB_SUCCESS == 0 */
                   1604: }
                   1605: 
                   1606: /****************************************************************************/
                   1607: /* Writes header information for 'msg'                                      */
                   1608: /* msg->hdr.length                                                                                                                     */
                   1609: /* msg->idx.offset                                                                                                                     */
                   1610: /* and msg->offset must be set prior to calling to this function                       */
                   1611: /* Returns 0 if everything ok                                               */
                   1612: /****************************************************************************/
                   1613: int SMBCALL smb_putmsghdr(smb_t* smb, smbmsg_t* msg)
                   1614: {
                   1615:        ushort  i;
                   1616:        ulong   hdrlen;
                   1617: 
                   1618:        if(smb->shd_fp==NULL) {
                   1619:                safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
                   1620:                return(SMB_ERR_NOT_OPEN);
                   1621:        }
                   1622: 
                   1623:        if(!smb_valid_hdr_offset(smb,msg->idx.offset))
                   1624:                return(SMB_ERR_HDR_OFFSET);
                   1625: 
                   1626:        clearerr(smb->shd_fp);
                   1627:        if(fseek(smb->shd_fp,msg->idx.offset,SEEK_SET)) {
                   1628:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1629:                        ,"%d '%s' seeking to %lu in index"
                   1630:                        ,get_errno(),STRERROR(get_errno()),msg->idx.offset);
                   1631:                return(SMB_ERR_SEEK);
                   1632:        }
                   1633:        /* Verify that the number of blocks required to stored the actual 
                   1634:           (calculated) header length does not exceed the number allocated. */
                   1635:        hdrlen=smb_getmsghdrlen(msg);
                   1636:        if(hdrlen>SMB_MAX_HDR_LEN) { /* headers are limited to 64k in size */
                   1637:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1638:                        ,"illegal message header length (%lu > %u)"
                   1639:                        ,hdrlen,SMB_MAX_HDR_LEN);
                   1640:                return(SMB_ERR_HDR_LEN);
                   1641:        }
                   1642:        if(smb_hdrblocks(hdrlen) > smb_hdrblocks(msg->hdr.length)) {
                   1643:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1644:                        ,"illegal header length increase: %lu (%lu blocks) vs %hu (%lu blocks)"
                   1645:                        ,hdrlen, smb_hdrblocks(hdrlen)
                   1646:                        ,msg->hdr.length, smb_hdrblocks(msg->hdr.length));
                   1647:                return(SMB_ERR_HDR_LEN);
                   1648:        }
                   1649:        msg->hdr.length=(ushort)hdrlen; /* store the actual header length */
                   1650:        /**********************************/
                   1651:        /* Set the message header ID here */
                   1652:        /**********************************/
                   1653:        memcpy(&msg->hdr.id,SHD_HEADER_ID,LEN_HEADER_ID);
                   1654: 
                   1655:        /************************************************/
                   1656:        /* Write the fixed portion of the header record */
                   1657:        /************************************************/
                   1658:        if(!fwrite(&msg->hdr,sizeof(msghdr_t),1,smb->shd_fp)) {
                   1659:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1660:                        ,"%d '%s' writing fixed portion of header record"
                   1661:                        ,get_errno(),STRERROR(get_errno()));
                   1662:                return(SMB_ERR_WRITE);
                   1663:        }
                   1664: 
                   1665:        /************************************************/
                   1666:        /* Write the data fields (each is fixed length) */
                   1667:        /************************************************/
                   1668:        for(i=0;i<msg->hdr.total_dfields;i++)
                   1669:                if(!fwrite(&msg->dfield[i],sizeof(dfield_t),1,smb->shd_fp)) {
                   1670:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1671:                                ,"%d '%s' writing data field"
                   1672:                                ,get_errno(),STRERROR(get_errno()));
                   1673:                        return(SMB_ERR_WRITE);
                   1674:                }
                   1675:        /*******************************************/
                   1676:        /* Write the variable length header fields */
                   1677:        /*******************************************/
                   1678:        for(i=0;i<msg->total_hfields;i++) {
                   1679:                if(!fwrite(&msg->hfield[i],sizeof(hfield_t),1,smb->shd_fp)) {
                   1680:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1681:                                ,"%d '%s' writing header field"
                   1682:                                ,get_errno(),STRERROR(get_errno()));
                   1683:                        return(SMB_ERR_WRITE);
                   1684:                }
                   1685:                if(msg->hfield[i].length                                         /* more then 0 bytes long */
                   1686:                        && !fwrite(msg->hfield_dat[i],msg->hfield[i].length,1,smb->shd_fp)) {
                   1687:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1688:                                ,"%d '%s' writing header field data"
                   1689:                                ,get_errno(),STRERROR(get_errno()));
                   1690:                        return(SMB_ERR_WRITE); 
                   1691:                }
                   1692:        }
                   1693: 
                   1694:        while(hdrlen%SHD_BLOCK_LEN) {
                   1695:                if(fputc(0,smb->shd_fp)!=0) {
                   1696:                        safe_snprintf(smb->last_error,sizeof(smb->last_error)
                   1697:                                ,"%d '%s' padding header block"
                   1698:                                ,get_errno(),STRERROR(get_errno()));
                   1699:                        return(SMB_ERR_WRITE);                     /* pad block with NULL */
                   1700:                }
                   1701:                hdrlen++; 
                   1702:        }
                   1703:        return fflush(smb->shd_fp);     /* SMB_SUCCESS == 0 */
                   1704: }
                   1705: 
                   1706: /****************************************************************************/
                   1707: /* Creates a sub-board's initial header file                                */
                   1708: /* Truncates and deletes other associated SMB files                                            */
                   1709: /****************************************************************************/
                   1710: int SMBCALL smb_create(smb_t* smb)
                   1711: {
                   1712:     char        str[MAX_PATH+1];
                   1713:        smbhdr_t        hdr;
                   1714: 
                   1715:        if(smb->shd_fp==NULL || smb->sdt_fp==NULL || smb->sid_fp==NULL) {
                   1716:                safe_snprintf(smb->last_error,sizeof(smb->last_error),"msgbase not open");
                   1717:                return(SMB_ERR_NOT_OPEN);
                   1718:        }
                   1719:        if(filelength(fileno(smb->shd_fp))>=(long)(sizeof(smbhdr_t)+sizeof(smbstatus_t))
                   1720:                && smb_locksmbhdr(smb)!=SMB_SUCCESS)  /* header exists, so lock it */
                   1721:                return(SMB_ERR_LOCK);
                   1722:        memset(&hdr,0,sizeof(smbhdr_t));
                   1723:        memcpy(hdr.id,SMB_HEADER_ID,LEN_HEADER_ID);     
                   1724:        hdr.version=SMB_VERSION;
                   1725:        hdr.length=sizeof(smbhdr_t)+sizeof(smbstatus_t);
                   1726:        smb->status.last_msg=smb->status.total_msgs=0;
                   1727:        smb->status.header_offset=sizeof(smbhdr_t)+sizeof(smbstatus_t);
                   1728:        rewind(smb->shd_fp);
                   1729:        fwrite(&hdr,1,sizeof(smbhdr_t),smb->shd_fp);
                   1730:        fwrite(&(smb->status),1,sizeof(smbstatus_t),smb->shd_fp);
                   1731:        rewind(smb->shd_fp);
                   1732:        chsize(fileno(smb->shd_fp),sizeof(smbhdr_t)+sizeof(smbstatus_t));
                   1733:        fflush(smb->shd_fp);
                   1734: 
                   1735:        rewind(smb->sdt_fp);
                   1736:        chsize(fileno(smb->sdt_fp),0L);
                   1737:        rewind(smb->sid_fp);
                   1738:        chsize(fileno(smb->sid_fp),0L);
                   1739: 
                   1740:        SAFEPRINTF(str,"%s.sda",smb->file);
                   1741:        remove(str);                                            /* if it exists, delete it */
                   1742:        SAFEPRINTF(str,"%s.sha",smb->file);
                   1743:        remove(str);                        /* if it exists, delete it */
                   1744:        SAFEPRINTF(str,"%s.sch",smb->file);
                   1745:        remove(str);
                   1746:        SAFEPRINTF(str,"%s.hash",smb->file);
                   1747:        remove(str);
                   1748:        smb_unlocksmbhdr(smb);
                   1749:        return(SMB_SUCCESS);
                   1750: }
                   1751: 
                   1752: /****************************************************************************/
                   1753: /* Returns number of data blocks required to store "length" amount of data  */
                   1754: /****************************************************************************/
                   1755: ulong SMBCALL smb_datblocks(ulong length)
                   1756: {
                   1757:        ulong blocks;
                   1758: 
                   1759:        blocks=length/SDT_BLOCK_LEN;
                   1760:        if(length%SDT_BLOCK_LEN)
                   1761:                blocks++;
                   1762:        return(blocks);
                   1763: }
                   1764: 
                   1765: /****************************************************************************/
                   1766: /* Returns number of header blocks required to store "length" size header   */
                   1767: /****************************************************************************/
                   1768: ulong SMBCALL smb_hdrblocks(ulong length)
                   1769: {
                   1770:        ulong blocks;
                   1771: 
                   1772:        blocks=length/SHD_BLOCK_LEN;
                   1773:        if(length%SHD_BLOCK_LEN)
                   1774:                blocks++;
                   1775:        return(blocks);
                   1776: }
                   1777: 
                   1778: /****************************************************************************/
                   1779: /* Returns difference from specified timezone and UTC/GMT                                      */
                   1780: /****************************************************************************/
                   1781: int SMBCALL smb_tzutc(short zone)
                   1782: {
                   1783:        int tz;
                   1784: 
                   1785:        if(OTHER_ZONE(zone))
                   1786:                return(zone);
                   1787: 
                   1788:        tz=zone&0xfff;
                   1789:        if(zone&(WESTERN_ZONE|US_ZONE)) {       /* West of UTC? */
                   1790:                if(zone&DAYLIGHT)
1.1.1.2 ! root     1791:                        tz-=60;                 /* ToDo: Daylight Saving Time adjustment is *not* always +60 minutes */
1.1       root     1792:                return(-tz);
                   1793:        }
                   1794:        return(tz);
                   1795: }
                   1796: 
                   1797: /****************************************************************************/
                   1798: /****************************************************************************/
                   1799: int SMBCALL smb_updatethread(smb_t* smb, smbmsg_t* remsg, ulong newmsgnum)
                   1800: {
                   1801:        int                     retval=SMB_ERR_NOT_FOUND;
                   1802:        ulong           nextmsgnum;
                   1803:        smbmsg_t        nextmsg;
                   1804: 
                   1805:        if(!remsg->hdr.thread_first) {  /* New msg is first reply */
                   1806:                if(remsg->idx.offset==0         /* index not read? */
                   1807:                        && (retval=smb_getmsgidx(smb,remsg))!=SMB_SUCCESS)
                   1808:                        return(retval);
                   1809:                if((retval=smb_lockmsghdr(smb,remsg))!=SMB_SUCCESS)
                   1810:                        return(retval);
                   1811:                if(!remsg->hdr.length           /* header not read? */
                   1812:                        && (retval=smb_getmsghdr(smb,remsg))!=SMB_SUCCESS)
                   1813:                        return(retval);
                   1814: 
                   1815:                remsg->hdr.thread_first=newmsgnum;
                   1816:                retval=smb_putmsghdr(smb,remsg);
                   1817:                smb_unlockmsghdr(smb,remsg);
                   1818:                return(retval);
                   1819:        }
                   1820: 
                   1821:        /* Search for last reply and extend chain */
                   1822:        memset(&nextmsg,0,sizeof(nextmsg));
                   1823:        nextmsgnum=remsg->hdr.thread_first;     /* start with first reply */
                   1824: 
                   1825:        while(1) {
                   1826:                nextmsg.idx.offset=0;
                   1827:                nextmsg.hdr.number=nextmsgnum;
                   1828:                if(smb_getmsgidx(smb, &nextmsg)!=SMB_SUCCESS) /* invalid thread origin */
                   1829:                        break;
                   1830:                if(smb_lockmsghdr(smb,&nextmsg)!=SMB_SUCCESS)
                   1831:                        break;
                   1832:                if(smb_getmsghdr(smb, &nextmsg)!=SMB_SUCCESS) {
                   1833:                        smb_unlockmsghdr(smb,&nextmsg); 
                   1834:                        break;
                   1835:                }
                   1836:                if(nextmsg.hdr.thread_next && nextmsg.hdr.thread_next!=nextmsgnum) {
                   1837:                        nextmsgnum=nextmsg.hdr.thread_next;
                   1838:                        smb_unlockmsghdr(smb,&nextmsg);
                   1839:                        smb_freemsgmem(&nextmsg);
                   1840:                        continue; 
                   1841:                }
                   1842:                nextmsg.hdr.thread_next=newmsgnum;
                   1843:                retval=smb_putmsghdr(smb,&nextmsg);
                   1844:                smb_unlockmsghdr(smb,&nextmsg);
                   1845:                smb_freemsgmem(&nextmsg);
                   1846:                break; 
                   1847:        }
                   1848: 
                   1849:        return(retval);
                   1850: }
                   1851: 
                   1852: /* 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.