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

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

unix.superglobalmegacorp.com

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