Annotation of libwww/Library/src/HTNewsLs.c, revision 2.13

2.1       frystyk     1: /*                                                                  HTNewsLs.c
                      2: **     NEWS (NNTP) GROUP LISTINGS
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.13    ! frystyk     6: **     @(#) $Id: HTNewsLs.c,v 2.12 1996/08/12 16:43:32 frystyk Exp $
2.1       frystyk     7: **
                      8: ** Authors
                      9: **     FTLO    Felix Lo
                     10: **     HFN     Henrik Frystyk <frystyk@w3.org>
2.12      frystyk    11: **     MP      Maciej Puzio <puzio@zodiac1.mimuw.edu.pl>
2.1       frystyk    12: **
                     13: ** History:
                     14: **     Oct 95  HFN     Written
2.12      frystyk    15: **  Mar 96  MP  Modified
2.1       frystyk    16: */
                     17: 
                     18: /* Library include files */
2.8       frystyk    19: #include "sysdep.h"
2.11      frystyk    20: #include "WWWUtil.h"
                     21: #include "WWWCore.h"
2.1       frystyk    22: #include "HTNDir.h"
                     23: #include "HTNews.h"
                     24: #include "HTNewsLs.h"                                   /* Implemented here */
                     25: 
                     26: #define DELIMITER              '\t'
2.5       frystyk    27: #define ATSIGN                 '@'
2.1       frystyk    28: 
2.12      frystyk    29: #define NEWS_TREE              "w3c-news"
                     30: 
2.1       frystyk    31: struct _HTStream {
2.8       frystyk    32:     const HTStreamClass *      isa;
2.1       frystyk    33:     HTRequest *                        request;
2.9       frystyk    34:     HTEOLState                 state;
2.1       frystyk    35:     HTNewsDir *                        dir;
                     36:     BOOL                       group;
                     37:     BOOL                       junk;
                     38:     char                       buffer[MAX_NEWS_LINE+1];
                     39:     int                                buflen;
                     40: };
                     41: 
2.12      frystyk    42: typedef struct _HTNewsCache {
                     43:     char *     host;
                     44:     HTArray *  cache;
                     45: } HTNewsCache;
                     46: 
                     47: PRIVATE HTNewsDirKey dir_key = HT_NDK_REFTHREAD;
                     48: PRIVATE HTNewsDirKey list_key = HT_NDK_GROUP;     /* Added by MP. */
2.1       frystyk    49: 
                     50: /* ------------------------------------------------------------------------- */
                     51: 
2.12      frystyk    52: /* Helper function added by MP. */
                     53: PRIVATE char* GetNewsGroupTitle (HTRequest* request)
                     54: {
                     55:     char * url = HTAnchor_physical(HTRequest_anchor(request));
                     56:     char * title = NULL;
                     57:     if (strrchr(url, '*'))
                     58:         StrAllocCopy(title, "Newsgroups: ");
                     59:     else
                     60:         StrAllocCopy(title, "Newsgroup: ");
                     61:     if (!strncasecomp(url, "news:", 5))
                     62:        StrAllocCat(title, url+5);
                     63:     else
                     64:        StrAllocCat(title, HTParse(url, "", PARSE_PATH));
                     65:     return title;
                     66: }
2.1       frystyk    67: 
2.12      frystyk    68: PRIVATE BOOL ParseList (HTNewsDir * dir, char * line)
2.1       frystyk    69: {
                     70:     char *ptr = line;
                     71:     while (*ptr && !WHITE(*ptr)) ptr++;
                     72:     *ptr = '\0';
2.12      frystyk    73:     /* Changed by MP */
                     74:     return (HTNewsDir_addGroupElement(dir, line, NO) != NULL);
2.1       frystyk    75: }
                     76: 
                     77: /*     ParseGroup
                     78: **     ----------
                     79: **     Extract the index number, subject etc, from a XOVER command. Expects
                     80: **     the following format of the line:
                     81: **
                     82: **             <index> <subject> <from> <data> <msgid> [*<thread>] ...
                     83: **
                     84: **     Returns YES if OK, NO on error
                     85: */
2.12      frystyk    86: PRIVATE BOOL ParseGroup (HTRequest * request, HTNewsDir *dir, char * line)
2.1       frystyk    87: {
                     88:     int index;
2.3       frystyk    89:     int refcnt=0;
2.5       frystyk    90:     time_t t=0;
                     91:     char *subject = line;
                     92:     char *from;
                     93:     char *date;
2.1       frystyk    94:     char *msgid;
2.5       frystyk    95:     char *ptr=NULL;
2.12      frystyk    96:     HTList* reflist = NULL;  /* Added by MP. */
2.1       frystyk    97:     while (*subject && *subject != DELIMITER) subject++;
2.5       frystyk    98:     *subject++ = '\0';                                 /* Index */
2.1       frystyk    99:     index = atoi(line);
2.5       frystyk   100:     from = subject;
2.1       frystyk   101:     while (*from && *from != DELIMITER) from++;
2.5       frystyk   102:     *from++ = '\0';                                    /* Subject */
                    103:     date = from;
                    104:     while (*date && *date != DELIMITER) {
                    105:        if (*date=='<' || *date=='(') {
                    106:            ptr = date+1;
                    107:            *date = '\0';
                    108:        }
                    109:        if (*date=='>' || *date==')') *date = '\0';
                    110:        date++;
                    111:     }
                    112:     *date++ = '\0';
                    113:     if (strchr(from, ATSIGN) && ptr) from = ptr;       /* From */
                    114:     msgid = date;
2.1       frystyk   115:     while (*msgid && *msgid != DELIMITER) msgid++;
2.5       frystyk   116:     *msgid++ = '\0';                                   /* Date */
                    117:     if (*msgid=='<') msgid++;
2.13    ! frystyk   118:     t = HTParseTime(date,  HTRequest_userProfile(request), YES);
2.5       frystyk   119:     ptr = msgid;
                    120:     while (*ptr && *ptr != DELIMITER) {
                    121:        if (*ptr=='>') *ptr = '\0';
                    122:        ptr++;
                    123:     }
                    124:     *ptr++ = '\0';                                     /* MsgId */
2.12      frystyk   125:     while (ptr && *ptr && !isdigit(*ptr)) {
                    126:         char* refstart = ptr;       /* Added by MP. */
                    127:         char* refcopy = NULL;
                    128:            char* refstop;
                    129:            while (*ptr && *ptr != DELIMITER && *ptr != ' ') ptr++;
                    130:            refstop = ptr - 1;
                    131:            *ptr++ = '\0';
                    132:         if (strlen(refstart) > 0)  /* Added by MP. */
                    133:            {
                    134:                refcnt++;
                    135:             if (*refstart == '<')  refstart++;
                    136:             if (*refstop == '>')  *refstop = '\0';
                    137:             if (reflist == NULL)  reflist = HTList_new();
                    138:             StrAllocCopy (refcopy, refstart);
                    139:             HTList_addObject (reflist, (void*) refcopy);
                    140:         }
                    141:     }
                    142:     /* Changed by MP. */
                    143:     return (HTNewsDir_addElement(dir, index, subject, from, t, msgid, 
                    144:         refcnt, reflist) != NULL);
                    145: }
                    146: 
                    147: /* ------------------------------------------------------------------------- */
                    148: /*                             NEWS CACHE                                   */
                    149: /* ------------------------------------------------------------------------- */
                    150: 
                    151: PRIVATE HTNewsCache * HTNewsCache_new (const char * newshost, HTArray * array)
                    152: {
                    153:     if (newshost && array) {
                    154:        HTNewsCache * me;
                    155:        if ((me = (HTNewsCache *) HT_CALLOC(1, sizeof(HTNewsCache))) == NULL)
                    156:            HT_OUTOFMEM("HTNewsCache_new");
                    157:        StrAllocCopy(me->host, newshost);
                    158:        me->cache = array;
                    159:        return me;
                    160:     }
                    161:     return NULL;
                    162: }
                    163: 
                    164: /*
                    165: **     Instead of just deleting we could save it to file.
                    166: */
                    167: PRIVATE int HTNewsCache_delete (void * context)
                    168: {
                    169:     HTNewsCache * me = (HTNewsCache *) context;
                    170:     if (me) {
                    171:        if (me->cache) {
                    172:            void ** data;
                    173:            char * line = (char *) HTArray_firstObject(me->cache, data);
                    174:            while (line) {
                    175:                HT_FREE(line);
                    176:                line = (char *) HTArray_nextObject(me->cache, data);
                    177:            }
                    178:            HTArray_delete(me->cache);
                    179:        }
                    180:        HT_FREE(me->host);
                    181:        if (PROT_TRACE) HTTrace("News Cache.. Deleted cache %p\n", me);
                    182:        HT_FREE(me);
                    183:        return YES;
2.1       frystyk   184:     }
2.12      frystyk   185:     return NO;
2.1       frystyk   186: }
                    187: 
                    188: /*
2.12      frystyk   189: **  Look for cached information for this news server
                    190: **  We store the information in a URL Tree so that we can have multiple
                    191: **  servers stored simultanously
                    192: */
                    193: PRIVATE HTNewsCache * HTNewsCache_find (HTRequest * request, const char * url)
                    194: {
                    195:     HTUTree * tree = NULL;
                    196:     if (request && url) {
                    197:        char * newshost = NULL;
                    198:        HTNewsCache * element = NULL;
                    199:        if (!strncasecomp(url, "news:", 5)) {
                    200:            HTUserProfile * up = HTRequest_userProfile(request);
                    201:            StrAllocCopy(newshost, HTUserProfile_news(up));
                    202:        } else if (!strncasecomp(url, "nntp:", 5)) {
                    203:            newshost = HTParse(url, "", PARSE_HOST);
                    204:        }
                    205: 
                    206:        /* If we have a news server then continue to find a URL tree */
                    207:        if (newshost) {
                    208:            char * colon = strchr(newshost, ':');
                    209:            int port = NEWS_PORT;
                    210:            if (colon ) {
                    211:                *(colon++) = '\0';                   /* Chop off port number */
                    212:                port = atoi(colon);
                    213:            }
                    214:            tree = HTUTree_find(NEWS_TREE, newshost, port);
                    215:            HT_FREE(newshost);
                    216:            if (!tree) {
                    217:                if (PROT_TRACE)
                    218:                    HTTrace("News Cache.. No information for `%s\'\n", url);
                    219:                return NULL;
                    220:            }
                    221: 
                    222:            /* Find a cache element (if any) */
                    223:            element = (HTNewsCache *) HTUTree_findNode(tree, "", "/");
                    224:            return element;
                    225:        }
                    226:     }
                    227:     return NULL;
                    228: }
                    229: 
                    230: PRIVATE BOOL HTNewsCache_update (HTRequest * request,
                    231:                                 const char * url, HTArray * array)
                    232: {
                    233:     HTUTree * tree = NULL;
                    234:     if (request && url) {
                    235:        char * newshost = NULL;
                    236:        if (!strncasecomp(url, "news:", 5)) {
                    237:            HTUserProfile * up = HTRequest_userProfile(request);
                    238:            StrAllocCopy(newshost, HTUserProfile_news(up));
                    239:        } else if (!strncasecomp(url, "nntp:", 5)) {
                    240:            newshost = HTParse(url, "", PARSE_HOST);
                    241:        }
                    242: 
                    243:        /* 
                    244:        **  If the news server was found then update the data entry. Otherwise
                    245:        **  create a new entry
                    246:        */
                    247:        if (newshost) {
                    248:            char * colon = strchr(newshost, ':');
                    249:            int port = NEWS_PORT;
                    250:            if (colon ) {
                    251:                *(colon++) = '\0';                   /* Chop off port number */
                    252:                port = atoi(colon);
                    253:            }
                    254:            tree = HTUTree_new(NEWS_TREE, newshost, port, HTNewsCache_delete);
                    255:            HT_FREE(newshost);
                    256:            if (!tree) {
                    257:                if (PROT_TRACE)HTTrace("News Cache.. Can't create tree\n");
                    258:                return NO;
                    259:            }
                    260: 
                    261:            /* Add new cache information to the tree */
                    262:            {
                    263:                HTNewsCache * element = NULL;
                    264:                BOOL status;
                    265:                if ((element=(HTNewsCache *) HTUTree_findNode(tree, "", "/"))){
                    266:                    element->cache = array;
                    267:                    status = YES;
                    268:                } else {
                    269:                    element = HTNewsCache_new(url, array);
                    270:                    status = HTUTree_addNode(tree, "", "/", element);
                    271:                }
                    272:                return status;
                    273:            }
                    274:        }
                    275:     }
                    276:     return NO;
                    277: }
                    278: 
                    279: /*
                    280: **     Before filter: Check whether we have a cache entry for this host
                    281: */
                    282: PUBLIC int HTNewsCache_before (HTRequest * request, void * context, int status)
                    283: {
                    284:     char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                    285:     HTNewsCache * element = HTNewsCache_find(request, url);
                    286:     HT_FREE(url);
                    287:     /*
                    288:     **  If we have found a cache object then create a new dir obejct and fill
                    289:     **  it with data from the cache
                    290:     */
                    291:     if (element) {
                    292:        char * title = GetNewsGroupTitle(request);
                    293:        HTNewsDir * dir = HTNewsDir_new(request, title, list_key, NO);
                    294:        void ** data;
                    295:        char * line = (char *) HTArray_firstObject(element->cache, data);
                    296:        while (line) {
                    297:            HTNewsDir_addGroupElement(dir, line, NO);
                    298:            line = (char *) HTArray_nextObject(element->cache, data);
                    299:        }
                    300: 
                    301:        /*
                    302:        **  After filling the new dir object we write it out and free it again
                    303:        */
                    304:        HTNewsDir_free(dir);
                    305:        HT_FREE(title);
                    306:        return HT_LOADED;
                    307:     }
                    308:     return HT_OK;
                    309: }
                    310: 
                    311: /*
                    312: **     After filter: Update the cache entry for this host
                    313: */
                    314: PUBLIC int HTNewsCache_after (HTRequest * request, void * context, int status)
                    315: {
                    316:     HTArray * array = (HTArray *) context;
                    317:     if (PROT_TRACE) HTTrace("News Cache.. AFTER filter\n");
                    318:     if (request && array) {
                    319:        char * url = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
                    320:        HTNewsCache_update(request, url, array);
                    321:        HT_FREE(url);
                    322:     }
                    323:     return HT_OK;
                    324: }
                    325: 
                    326: /* ------------------------------------------------------------------------- */
                    327: 
                    328: /*
2.1       frystyk   329: **     Searches for News line until buffer fills up or a CRLF or LF is found
                    330: */
2.8       frystyk   331: PRIVATE int HTNewsList_put_block (HTStream * me, const char * b, int l)
2.1       frystyk   332: {
                    333:     while (l-- > 0) {
                    334:        if (me->state == EOL_FCR) {
                    335:            if (*b == LF && me->buflen) {
                    336:                if (!me->junk) {
                    337:                    *(me->buffer+me->buflen) = '\0';
2.12      frystyk   338:                    me->group ? ParseGroup(me->request, me->dir, me->buffer) :
2.1       frystyk   339:                        ParseList(me->dir, me->buffer);
                    340:                } else
                    341:                    me->junk = NO;                         /* back to normal */
                    342:            }
                    343:            me->buflen = 0;
                    344:            me->state = EOL_BEGIN;
                    345:        } else if (*b == CR) {
                    346:            me->state = EOL_FCR;
                    347:        } else if (*b == LF && me->buflen) {
                    348:            if (!me->junk) {
                    349:                *(me->buffer+me->buflen) = '\0';
2.12      frystyk   350:                me->group ? ParseGroup(me->request, me->dir, me->buffer) :
2.1       frystyk   351:                    ParseList(me->dir, me->buffer);
                    352:            } else
                    353:                me->junk = NO;                             /* back to normal */
                    354:            me->buflen = 0;
                    355:            me->state = EOL_BEGIN;
                    356:        } else {
                    357:            *(me->buffer+me->buflen++) = *b;
                    358:            if (me->buflen >= MAX_NEWS_LINE) {
                    359:                if (PROT_TRACE)
2.7       eric      360:                    HTTrace("News Dir.... Line too long - chopped\n");
2.1       frystyk   361:                *(me->buffer+me->buflen) = '\0';
2.12      frystyk   362:                me->group ? ParseGroup(me->request, me->dir, me->buffer) :
2.1       frystyk   363:                    ParseList(me->dir, me->buffer);
                    364:                me->buflen = 0;
                    365:                me->junk = YES;
                    366:            }
                    367:        }
                    368:        b++;
                    369:     }
                    370:     return HT_OK;
                    371: }
                    372: 
                    373: PRIVATE int HTNewsList_put_character (HTStream * me, char ch)
                    374: {
                    375:     return HTNewsList_put_block(me, &ch, 1);
                    376: }
                    377: 
2.8       frystyk   378: PRIVATE int HTNewsList_put_string (HTStream * me, const char * s)
2.1       frystyk   379: {
                    380:     return HTNewsList_put_block(me, s, (int) strlen(s));
                    381: }
                    382: 
                    383: PRIVATE int HTNewsList_flush (HTStream * me)
                    384: {
                    385:     return HT_OK;
                    386: }
                    387: 
                    388: PRIVATE int HTNewsList_free (HTStream * me)
                    389: {
2.12      frystyk   390:     HTNewsList_put_character (me, '\n');  /* to flush the last item; added by MP. */
2.1       frystyk   391:     HTNewsDir_free(me->dir);
2.6       frystyk   392:     HT_FREE(me);
2.1       frystyk   393:     return HT_OK;
                    394: }
                    395: 
2.4       frystyk   396: PRIVATE int HTNewsList_abort (HTStream * me, HTList * e)
2.1       frystyk   397: {
2.7       eric      398:     if (PROT_TRACE) HTTrace("News Dir.... ABORTING...\n");
2.1       frystyk   399:     HTNewsList_free(me);
                    400:     return HT_ERROR;
                    401: }
                    402: 
2.8       frystyk   403: PRIVATE const HTStreamClass HTNewsListClass =
2.1       frystyk   404: {               
                    405:     "NewsList",
                    406:     HTNewsList_flush,
                    407:     HTNewsList_free,
                    408:     HTNewsList_abort,
                    409:     HTNewsList_put_character,
                    410:     HTNewsList_put_string,
                    411:     HTNewsList_put_block
                    412: };
                    413: 
                    414: PUBLIC HTStream *HTNewsList (HTRequest *       request,
                    415:                             void *             param,  
                    416:                             HTFormat           input_format,
                    417:                             HTFormat           output_format,
                    418:                             HTStream *         output_stream)
                    419: {
2.6       frystyk   420:     HTStream *me;
                    421:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    422:         HT_OUTOFMEM("HTNewsList_new");
2.1       frystyk   423:     me->isa = &HTNewsListClass;
                    424:     me->request = request;
                    425:     me->state = EOL_BEGIN;
2.12      frystyk   426:     {
                    427:        char * title = GetNewsGroupTitle(request);
                    428:        me->dir = HTNewsDir_new(request, title, list_key,YES);
                    429:        HT_FREE(title);
                    430:     }
                    431:     /* Modified by MP. */
2.6       frystyk   432:     if (me->dir == NULL) HT_FREE(me);
2.1       frystyk   433:     return me;
                    434: }
                    435: 
                    436: PUBLIC HTStream *HTNewsGroup (HTRequest *      request,
                    437:                              void *            param,  
                    438:                              HTFormat          input_format,
                    439:                              HTFormat          output_format,
                    440:                              HTStream *        output_stream)
                    441: {
2.12      frystyk   442:     HTStream * me;
2.6       frystyk   443:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    444:         HT_OUTOFMEM("HTNewsList_new");
2.1       frystyk   445:     me->isa = &HTNewsListClass;
                    446:     me->request = request;
                    447:     me->state = EOL_BEGIN;
                    448:     me->group = YES;
2.12      frystyk   449:     {
                    450:        char * title = GetNewsGroupTitle(request);
                    451:        me->dir = HTNewsDir_new(request, title, dir_key, YES);
                    452:        HT_FREE(title);
                    453:     }
                    454:     /* Modified by MP. */
2.6       frystyk   455:     if (me->dir == NULL) HT_FREE(me);
2.1       frystyk   456:     return me;
                    457: }

Webmaster