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