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

1.1       root        1: /* smbhash.c */
                      2: 
                      3: /* Synchronet message base (SMB) hash-related functions */
                      4: 
1.1.1.2 ! root        5: /* $Id: smbhash.c,v 1.26 2009/11/05 17:05:13 rswindell Exp $ */
1.1       root        6: 
                      7: /****************************************************************************
                      8:  * @format.tab-size 4          (Plain Text/Source Code File Header)                    *
                      9:  * @format.use-tabs true       (see http://www.synchro.net/ptsc_hdr.html)              *
                     10:  *                                                                                                                                                     *
1.1.1.2 ! root       11:  * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html         *
1.1       root       12:  *                                                                                                                                                     *
                     13:  * This library is free software; you can redistribute it and/or                       *
                     14:  * modify it under the terms of the GNU Lesser General Public License          *
                     15:  * as published by the Free Software Foundation; either version 2                      *
                     16:  * of the License, or (at your option) any later version.                                      *
                     17:  * See the GNU Lesser General Public License for more details: lgpl.txt or     *
                     18:  * http://www.fsf.org/copyleft/lesser.html                                                                     *
                     19:  *                                                                                                                                                     *
                     20:  * Anonymous FTP access to the most recent released source is available at     *
                     21:  * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net     *
                     22:  *                                                                                                                                                     *
                     23:  * Anonymous CVS access to the development source and modification history     *
                     24:  * is available at cvs.synchro.net:/cvsroot/sbbs, example:                                     *
                     25:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs login                       *
                     26:  *     (just hit return, no password is necessary)                                                     *
                     27:  * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src                *
                     28:  *                                                                                                                                                     *
                     29:  * For Synchronet coding style and modification guidelines, see                                *
                     30:  * http://www.synchro.net/source.html                                                                          *
                     31:  *                                                                                                                                                     *
                     32:  * You are encouraged to submit any modifications (preferably in Unix diff     *
                     33:  * format) via e-mail to [email protected]                                                                      *
                     34:  *                                                                                                                                                     *
                     35:  * Note: If this box doesn't appear square, then you need to fix your tabs.    *
                     36:  ****************************************************************************/
                     37: 
                     38: #include <time.h>              /* time()       */
                     39: #include <string.h>            /* strdup() */
                     40: #include "smblib.h"
                     41: #include "md5.h"
                     42: #include "crc16.h"
                     43: #include "crc32.h"
                     44: #include "genwrap.h"
                     45: 
1.1.1.2 ! root       46: /* If return value is SMB_ERR_NOT_FOUND, hash file is left open */
1.1       root       47: int SMBCALL smb_findhash(smb_t* smb, hash_t** compare, hash_t* found_hash, 
                     48:                                                 long source_mask, BOOL mark)
                     49: {
                     50:        int             retval;
                     51:        BOOL    found=FALSE;
                     52:        size_t  c,count;
                     53:        hash_t  hash;
                     54: 
                     55:        if(found_hash!=NULL)
                     56:                memset(found_hash,0,sizeof(hash_t));
                     57: 
                     58:        if((retval=smb_open_hash(smb))!=SMB_SUCCESS)
                     59:                return(retval);
                     60: 
                     61:        COUNT_LIST_ITEMS(compare, count);
                     62: 
1.1.1.2 ! root       63:        if(count && source_mask!=SMB_HASH_SOURCE_NONE) {
1.1       root       64: 
                     65:                rewind(smb->hash_fp);
1.1.1.2 ! root       66:                clearerr(smb->hash_fp);
1.1       root       67:                while(!feof(smb->hash_fp)) {
                     68:                        if(smb_fread(smb,&hash,sizeof(hash),smb->hash_fp)!=sizeof(hash))
                     69:                                break;
                     70: 
                     71:                        if(hash.flags==0)
                     72:                                continue;               /* invalid hash record (!?) */
                     73: 
                     74:                        if((source_mask&(1<<hash.source))==0)   /* not checking this source type */
                     75:                                continue;
                     76: 
                     77:                        for(c=0;compare[c]!=NULL;c++) {
                     78: 
                     79:                                if(compare[c]->source!=hash.source)
                     80:                                        continue;       /* wrong source */
                     81:                                if(compare[c]->length!=hash.length)
                     82:                                        continue;       /* wrong source length */
                     83:                                if(compare[c]->flags&SMB_HASH_MARKED)
                     84:                                        continue;       /* already marked */
1.1.1.2 ! root       85:                                if((compare[c]->flags&SMB_HASH_PROC_COMP_MASK)!=(hash.flags&SMB_HASH_PROC_COMP_MASK))
1.1       root       86:                                        continue;       /* wrong pre-process flags */
                     87:                                if((compare[c]->flags&hash.flags&SMB_HASH_MASK)==0)     
                     88:                                        continue;       /* no matching hashes */
1.1.1.2 ! root       89:                                if((compare[c]->flags&hash.flags&SMB_HASH_CRC16)
1.1       root       90:                                        && compare[c]->crc16!=hash.crc16)
                     91:                                        continue;       /* wrong crc-16 */
1.1.1.2 ! root       92:                                if((compare[c]->flags&hash.flags&SMB_HASH_CRC32)
1.1       root       93:                                        && compare[c]->crc32!=hash.crc32)
                     94:                                        continue;       /* wrong crc-32 */
1.1.1.2 ! root       95:                                if((compare[c]->flags&hash.flags&SMB_HASH_MD5)
1.1       root       96:                                        && memcmp(compare[c]->md5,hash.md5,sizeof(hash.md5)))
1.1.1.2 ! root       97:                                        continue;       /* wrong MD5 */
1.1       root       98:                                
                     99:                                /* successful match! */
                    100:                                break;  /* can't match more than one, so stop comparing */
                    101:                        }
                    102: 
                    103:                        if(compare[c]==NULL)
                    104:                                continue;       /* no match */
                    105: 
                    106:                        found=TRUE;
                    107: 
                    108:                        if(found_hash!=NULL)
                    109:                                memcpy(found_hash,&hash,sizeof(hash));
                    110: 
                    111:                        if(!mark)
                    112:                                break;
                    113: 
                    114:                        compare[c]->flags|=SMB_HASH_MARKED;
                    115:                }
                    116:                if(found) {
                    117:                        smb_close_hash(smb);
                    118:                        return(SMB_SUCCESS);
                    119:                }
                    120:        }
                    121: 
                    122:        /* hash file left open */
                    123:        return(SMB_ERR_NOT_FOUND);
                    124: }
                    125: 
                    126: int SMBCALL smb_addhashes(smb_t* smb, hash_t** hashes, BOOL skip_marked)
                    127: {
                    128:        int             retval;
                    129:        size_t  h;
                    130: 
                    131:        COUNT_LIST_ITEMS(hashes, h);
                    132:        if(!h)  /* nothing to add */
                    133:                return(SMB_SUCCESS);
                    134: 
                    135:        if((retval=smb_open_hash(smb))!=SMB_SUCCESS)
                    136:                return(retval);
                    137: 
                    138:        fseek(smb->hash_fp,0,SEEK_END);
                    139: 
                    140:        for(h=0;hashes[h]!=NULL;h++) {
                    141: 
                    142:                /* skip hashes marked by smb_findhash() */
                    143:                if(skip_marked && hashes[h]->flags&SMB_HASH_MARKED)     
                    144:                        continue;       
                    145:        
                    146:                /* can't think of any reason to strip SMB_HASH_MARKED flag right now */
                    147:                if(smb_fwrite(smb,hashes[h],sizeof(hash_t),smb->hash_fp)!=sizeof(hash_t)) {
                    148:                        retval=SMB_ERR_WRITE;
                    149:                        break;
                    150:                }
                    151:        }
                    152: 
                    153:        smb_close_hash(smb);
                    154: 
                    155:        return(retval);
                    156: }
                    157: 
                    158: static char* strip_chars(uchar* dst, const uchar* src, uchar* set)
                    159: {
                    160:        while(*src) {
                    161:                if(strchr(set,*src)==NULL)
                    162:                        *(dst++)=*src;
                    163:                src++;
                    164:        }
                    165:        *dst=0;
                    166: 
                    167:        return((char *)dst);
                    168: }
                    169: 
1.1.1.2 ! root      170: static char* strip_ctrla(uchar* dst, const uchar* src)
        !           171: {
        !           172:        while(*src) {
        !           173:                if(*src==CTRL_A) {
        !           174:                        src++;
        !           175:                        if(*src)
        !           176:                                src++;
        !           177:                }
        !           178:                else
        !           179:                        *(dst++)=*(src++);
        !           180:        }
        !           181:        *dst=0;
        !           182: 
        !           183:        return((char *)dst);
        !           184: }
        !           185: 
1.1       root      186: /* Allocates and calculates hashes of data (based on flags)                                    */
                    187: /* Returns NULL on failure                                                                                                     */
                    188: hash_t* SMBCALL smb_hash(ulong msgnum, ulong t, unsigned source, unsigned flags
                    189:                                                 ,const void* data, size_t length)
                    190: {
                    191:        hash_t* hash;
                    192: 
1.1.1.2 ! root      193:        if(length==0)           /* Don't hash 0-length sources (e.g. empty/blank message bodies) */
        !           194:                return(NULL);
        !           195: 
1.1       root      196:        if((hash=(hash_t*)malloc(sizeof(hash_t)))==NULL)
                    197:                return(NULL);
                    198: 
                    199:        memset(hash,0,sizeof(hash_t));
                    200:        hash->number=msgnum;
                    201:        hash->time=t;
                    202:        hash->length=length;
                    203:        hash->source=source;
                    204:        hash->flags=flags;
                    205:        if(flags&SMB_HASH_CRC16)
                    206:                hash->crc16=crc16((char*)data,length);
                    207:        if(flags&SMB_HASH_CRC32)
                    208:                hash->crc32=crc32((char*)data,length);
                    209:        if(flags&SMB_HASH_MD5)
                    210:                MD5_calc(hash->md5,data,length);
                    211: 
                    212:        return(hash);
                    213: }
                    214: 
                    215: /* Allocates and calculates hashes of data (based on flags)                                    */
                    216: /* Supports string hash "pre-processing" (e.g. lowercase, strip whitespace)    */
                    217: /* Returns NULL on failure                                                                                                     */
                    218: hash_t* SMBCALL smb_hashstr(ulong msgnum, ulong t, unsigned source, unsigned flags
                    219:                                                        ,const char* str)
                    220: {
                    221:        char*   p=(char *)str;
                    222:        hash_t* hash;
                    223: 
                    224:        if(flags&SMB_HASH_PROC_MASK) {  /* string pre-processing */
                    225:                if((p=strdup(str))==NULL)
                    226:                        return(NULL);
1.1.1.2 ! root      227:                if(flags&SMB_HASH_STRIP_CTRL_A)
        !           228:                        strip_ctrla(p,p);
1.1       root      229:                if(flags&SMB_HASH_STRIP_WSP)
1.1.1.2 ! root      230:                        strip_chars(p,p," \t\r\n");
1.1       root      231:                if(flags&SMB_HASH_LOWERCASE)
                    232:                        strlwr(p);
                    233:        }
                    234:        
                    235:        hash=smb_hash(msgnum, t, source, flags, p, strlen(p));
                    236: 
                    237:        if(p!=str)      /* duped string */
                    238:                free(p);
                    239: 
                    240:        return(hash);
                    241: }
                    242: 
1.1.1.2 ! root      243: /* Allocates and calculates all hashes for a single message                                    */
1.1       root      244: /* Returns NULL on failure                                                                                                     */
1.1.1.2 ! root      245: hash_t** SMBCALL smb_msghashes(smbmsg_t* msg, const uchar* body, long source_mask)
1.1       root      246: {
                    247:        size_t          h=0;
                    248:        uchar           flags=SMB_HASH_CRC16|SMB_HASH_CRC32|SMB_HASH_MD5;
                    249:        hash_t**        hashes; /* This is a NULL-terminated list of hashes */
                    250:        hash_t*         hash;
                    251:        time_t          t=time(NULL);
                    252: 
                    253:        if((hashes=(hash_t**)malloc(sizeof(hash_t*)*(SMB_HASH_SOURCE_TYPES+1)))==NULL)
                    254:                return(NULL);
                    255: 
                    256:        memset(hashes, 0, sizeof(hash_t*)*(SMB_HASH_SOURCE_TYPES+1));
                    257: 
1.1.1.2 ! root      258:        if(msg->id!=NULL && (source_mask&(1<<SMB_HASH_SOURCE_MSG_ID)) &&
1.1       root      259:                (hash=smb_hashstr(msg->hdr.number, t, SMB_HASH_SOURCE_MSG_ID, flags, msg->id))!=NULL)
                    260:                hashes[h++]=hash;
                    261: 
1.1.1.2 ! root      262:        if(msg->ftn_msgid!=NULL && (source_mask&(1<<SMB_HASH_SOURCE_FTN_ID)) &&
1.1       root      263:                (hash=smb_hashstr(msg->hdr.number, t, SMB_HASH_SOURCE_FTN_ID, flags, msg->ftn_msgid))!=NULL)
                    264:                hashes[h++]=hash;
                    265: 
1.1.1.2 ! root      266:        if(body!=NULL && (source_mask&(1<<SMB_HASH_SOURCE_BODY)) &&
        !           267:                (hash=smb_hashstr(msg->hdr.number, t, SMB_HASH_SOURCE_BODY, flags|SMB_HASH_STRIP_WSP|SMB_HASH_STRIP_CTRL_A, body))!=NULL)
1.1       root      268:                hashes[h++]=hash;
                    269: 
1.1.1.2 ! root      270:        if(msg->subj!=NULL && (source_mask&(1<<SMB_HASH_SOURCE_SUBJECT))) {
        !           271:                char*   p=msg->subj;
        !           272:                while(*p) {
        !           273:                        char* tp=strchr(p,':');
        !           274:                        char* sp=strchr(p,' ');
        !           275:                        if(tp!=NULL && (sp==NULL || tp<sp)) {
        !           276:                                p=tp+1;
        !           277:                                SKIP_WHITESPACE(p);
        !           278:                                continue;
        !           279:                        }
        !           280:                        break;
        !           281:                }
        !           282:                if((hash=smb_hashstr(msg->hdr.number, t, SMB_HASH_SOURCE_SUBJECT, flags, p))!=NULL)
        !           283:                        hashes[h++]=hash;
        !           284:        }
        !           285: 
1.1       root      286:        return(hashes);
                    287: }
                    288: 
1.1.1.2 ! root      289: void SMBCALL smb_freehashes(hash_t** hashes)
        !           290: {
        !           291:        size_t          n;
        !           292: 
        !           293:        FREE_LIST(hashes,n);
        !           294: }
        !           295: 
1.1       root      296: /* Calculates and stores the hashes for a single message                                       */
                    297: int SMBCALL smb_hashmsg(smb_t* smb, smbmsg_t* msg, const uchar* text, BOOL update)
                    298: {
                    299:        size_t          n;
                    300:        int                     retval=SMB_SUCCESS;
                    301:        hash_t          found;
                    302:        hash_t**        hashes; /* This is a NULL-terminated list of hashes */
                    303: 
1.1.1.2 ! root      304:        if(smb->status.attr&(SMB_EMAIL|SMB_NOHASH))
1.1       root      305:                return(SMB_SUCCESS);
                    306: 
1.1.1.2 ! root      307:        hashes=smb_msghashes(msg,text,SMB_HASH_SOURCE_DUPE);
1.1       root      308: 
1.1.1.2 ! root      309:        if(smb_findhash(smb, hashes, &found, SMB_HASH_SOURCE_DUPE, update)==SMB_SUCCESS && !update) {
1.1       root      310:                retval=SMB_DUPE_MSG;
                    311:                safe_snprintf(smb->last_error,sizeof(smb->last_error)
                    312:                        ,"duplicate %s: %s found in message #%lu"
                    313:                        ,smb_hashsourcetype(found.source)
                    314:                        ,smb_hashsource(msg,found.source)
                    315:                        ,found.number);
                    316:        } else
                    317:                if((retval=smb_addhashes(smb,hashes,/* skip_marked? */TRUE))==SMB_SUCCESS)
                    318:                        msg->flags|=MSG_FLAG_HASHED;
                    319: 
                    320:        FREE_LIST(hashes,n);
                    321: 
                    322:        return(retval);
                    323: }
                    324: 
                    325: /* length=0 specifies ASCIIZ data                                                                                      */
                    326: int SMBCALL smb_getmsgidx_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
                    327:                                                                 ,unsigned flags, const void* data, size_t length)
                    328: {
                    329:        int                     retval;
                    330:        size_t          n;
                    331:        hash_t**        hashes;
                    332:        hash_t          found;
                    333: 
                    334:        if((hashes=(hash_t**)malloc(sizeof(hash_t*)*2))==NULL)
                    335:                return(SMB_ERR_MEM);
                    336: 
                    337:        if(length==0)
                    338:                hashes[0]=smb_hashstr(0,0,source,flags,data);
                    339:        else
                    340:                hashes[0]=smb_hash(0,0,source,flags,data,length);
                    341:        if(hashes[0]==NULL)
                    342:                return(SMB_ERR_MEM);
                    343: 
                    344:        hashes[1]=NULL; /* terminate list */
                    345: 
                    346:        if((retval=smb_findhash(smb, hashes, &found, 1<<source, FALSE))==SMB_SUCCESS) {
                    347:                if(found.number==0)
                    348:                        retval=SMB_FAILURE;     /* use better error value here? */
                    349:                else {
                    350:                        msg->hdr.number=found.number;
                    351:                        retval=smb_getmsgidx(smb, msg);
                    352:                }
                    353:        }
                    354: 
                    355:        FREE_LIST(hashes,n);
                    356: 
                    357:        return(retval);
                    358: }
                    359: 
                    360: int SMBCALL smb_getmsghdr_by_hash(smb_t* smb, smbmsg_t* msg, unsigned source
                    361:                                                                 ,unsigned flags, const void* data, size_t length)
                    362: {
                    363:        int retval;
                    364: 
                    365:        if((retval=smb_getmsgidx_by_hash(smb,msg,source,flags,data,length))!=SMB_SUCCESS)
                    366:                return(retval);
                    367: 
                    368:        if((retval=smb_lockmsghdr(smb,msg))!=SMB_SUCCESS)
                    369:                return(retval);
                    370: 
                    371:        retval=smb_getmsghdr(smb,msg);
                    372: 
                    373:        smb_unlockmsghdr(smb,msg); 
                    374: 
                    375:        return(retval);
                    376: }
                    377: 
1.1.1.2 ! root      378: uint16_t SMBCALL smb_subject_crc(const char* subj)
1.1       root      379: {
                    380:        char*   str;
1.1.1.2 ! root      381:        uint16_t        crc;
1.1       root      382: 
                    383:        if(subj==NULL)
1.1.1.2 ! root      384:                return(0);
1.1       root      385: 
                    386:        while(!strnicmp(subj,"RE:",3)) {
                    387:                subj+=3;
                    388:                while(*subj==' ')
                    389:                        subj++; 
                    390:        }
                    391: 
                    392:        if((str=strdup(subj))==NULL)
                    393:                return(0xffff);
                    394: 
                    395:        strlwr(str);
                    396:        crc=crc16(str,0 /* auto-length */);
                    397:        free(str);
                    398: 
                    399:        return(crc);
                    400: }
                    401: 
1.1.1.2 ! root      402: uint16_t SMBCALL smb_name_crc(const char* name)
1.1       root      403: {
                    404:        char*   str;
1.1.1.2 ! root      405:        uint16_t        crc;
1.1       root      406: 
                    407:        if(name==NULL)
1.1.1.2 ! root      408:                return(0);
1.1       root      409: 
                    410:        if((str=strdup(name))==NULL)
                    411:                return(0xffff);
                    412: 
                    413:        strlwr(str);
                    414:        crc=crc16(str,0 /* auto-length */);
                    415:        free(str);
                    416: 
                    417:        return(crc);
                    418: }

unix.superglobalmegacorp.com

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