Annotation of libwww/Library/src/HTFormat.c, revision 1.56.2.1

1.55      frystyk     1: /*                                                                  HTFormat.c
                      2: **     MANAGE DIFFERENT FILE FORMATS
                      3: **
                      4: **     (c) COPYRIGHT CERN 1994.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
1.1       timbl       6: **
                      7: ** Bugs:
                      8: **     Assumes the incoming stream is ASCII, rather than a local file
                      9: **     format, and so ALWAYS converts from ASCII on non-ASCII machines.
                     10: **     Therefore, non-ASCII machines can't read local files.
1.2       timbl      11: **
1.45      duns       12: ** HISTORY:
1.52      frystyk    13: **     8 Jul 94  FM    Insulate free() from _free structure element.
                     14: **     8 Nov 94  HFN   Changed a lot to make reentrant
1.2       timbl      15: */
                     16: 
1.52      frystyk    17: /* Library Include files */
1.56.2.1! frystyk    18: #include "tcp.h"
        !            19: #include "HTUtils.h"
        !            20: #include "HTString.h"
1.52      frystyk    21: #include "HTTCP.h"
1.56.2.1! frystyk    22: #include "HTFWrite.h"
1.52      frystyk    23: #include "HTGuess.h"
                     24: #include "HTThread.h"
                     25: #include "HTError.h"
                     26: #include "HTFormat.h"                                   /* Implemented here */
1.2       timbl      27: 
1.52      frystyk    28: /* Public variables */
                     29: PUBLIC float HTMaxSecs = 1e10;         /* No effective limit */
                     30: PUBLIC float HTMaxLength = 1e10;       /* No effective limit */
                     31: PUBLIC HTList * HTConversions = NULL;
1.1       timbl      32: 
1.52      frystyk    33: /* Typedefs and global variable local to thid module */
1.10      timbl      34: struct _HTStream {
                     35:        CONST HTStreamClass *           isa;
                     36:        BOOL                    had_cr;
                     37:        HTStream *              sink;
                     38: };
1.2       timbl      39: 
1.52      frystyk    40: /* Accept-Encoding and Accept-Language */
1.17      luotonen   41: typedef struct _HTAcceptNode {
                     42:     HTAtom *   atom;
                     43:     float      quality;
                     44: } HTAcceptNode;
                     45: 
1.52      frystyk    46: /* ------------------------------------------------------------------------- */
1.17      luotonen   47: 
1.52      frystyk    48: /*
                     49: **   This function replaces the code in HTRequest_delete() in order to keep
                     50: **   the data structure hidden (it is NOT a joke!)
                     51: **   Henrik 14/03-94
1.2       timbl      52: */
1.52      frystyk    53: PUBLIC void HTFormatDelete ARGS1(HTRequest *, request)
1.31      frystyk    54: {
1.56      frystyk    55:     if (request && request->conversions) {
                     56:        HTList *cur = request->conversions;
                     57:        HTPresentation *pres;
                     58:        while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
                     59:            FREE(pres->command); /* Leak fixed AL 6 Feb 1994 */
                     60:            free(pres);
                     61:        }
                     62:        HTList_delete(request->conversions);
                     63:        request->conversions = NULL;
1.31      frystyk    64:     }
                     65: }
                     66: 
1.2       timbl      67: 
                     68: /*     Define a presentation system command for a content-type
                     69: **     -------------------------------------------------------
1.52      frystyk    70: ** INPUT:
                     71: **     conversions:    The list of conveters and presenters
                     72: **     representation: the MIME-style format name
                     73: **     command:        the MAILCAP-style command template
                     74: **     quality:        A degradation faction [0..1]
                     75: **     maxbytes:       A limit on the length acceptable as input (0 infinite)
                     76: **     maxsecs:        A limit on the time user will wait (0 for infinity)
1.2       timbl      77: */
1.49      howcome    78: PUBLIC void HTSetPresentation ARGS7(
1.12      timbl      79:        HTList *,       conversions,
                     80:        CONST char *,   representation,
                     81:        CONST char *,   command,
1.52      frystyk    82:        CONST char *,   test_command,  /* HWL 27/9/94: mailcap functionality */
1.12      timbl      83:        float,          quality,
                     84:        float,          secs, 
1.52      frystyk    85:        float,          secs_per_byte)
                     86: {
1.2       timbl      87:     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
                     88:     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
                     89:     
                     90:     pres->rep = HTAtom_for(representation);
                     91:     pres->rep_out = WWW_PRESENT;               /* Fixed for now ... :-) */
                     92:     pres->converter = HTSaveAndExecute;                /* Fixed for now ...     */
                     93:     pres->quality = quality;
                     94:     pres->secs = secs;
                     95:     pres->secs_per_byte = secs_per_byte;
                     96:     pres->rep = HTAtom_for(representation);
1.49      howcome    97:     pres->command = NULL;
1.2       timbl      98:     StrAllocCopy(pres->command, command);
1.49      howcome    99:     pres->test_command = NULL;
                    100:     StrAllocCopy(pres->test_command, test_command);
1.12      timbl     101:     HTList_addObject(conversions, pres);
1.2       timbl     102: }
                    103: 
                    104: 
                    105: /*     Define a built-in function for a content-type
                    106: **     ---------------------------------------------
                    107: */
1.12      timbl     108: PUBLIC void HTSetConversion ARGS7(
                    109:        HTList *,       conversions,
                    110:        CONST char *,   representation_in,
                    111:        CONST char *,   representation_out,
1.6       timbl     112:        HTConverter*,   converter,
1.12      timbl     113:        float,          quality,
                    114:        float,          secs, 
1.52      frystyk   115:        float,          secs_per_byte)
                    116: {
1.2       timbl     117:     HTPresentation * pres = (HTPresentation *)malloc(sizeof(HTPresentation));
                    118:     if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
                    119:     
                    120:     pres->rep = HTAtom_for(representation_in);
                    121:     pres->rep_out = HTAtom_for(representation_out);
                    122:     pres->converter = converter;
                    123:     pres->command = NULL;              /* Fixed */
1.49      howcome   124:     pres->test_command = NULL;
1.2       timbl     125:     pres->quality = quality;
                    126:     pres->secs = secs;
                    127:     pres->secs_per_byte = secs_per_byte;
1.12      timbl     128:     HTList_addObject(conversions, pres);
1.56      frystyk   129: }
                    130: 
                    131: 
                    132: /*
                    133: **     Cleanup memory after the GLOBAL list of converters. Note that there
                    134: **     is also a LOCAL conversion list associated with each HTRequest
                    135: **     structure. Written by Eric Sink, eric@spyglass.com
                    136: */
                    137: PUBLIC void HTDisposeConversions NOARGS
                    138: {
                    139:     if (HTConversions) {
                    140:        HTList_delete(HTConversions);
                    141:        HTConversions = NULL;
                    142:     }
1.2       timbl     143: }
1.1       timbl     144: 
                    145: 
1.17      luotonen  146: PUBLIC void HTAcceptEncoding ARGS3(HTList *,   list,
                    147:                                   char *,      enc,
                    148:                                   float,       quality)
                    149: {
                    150:     HTAcceptNode * node;
                    151:     char * cur;
                    152: 
                    153:     if (!list || !enc || !*enc) return;
                    154: 
                    155:     for(cur=enc; *cur; cur++) *cur=TOLOWER(*cur);
                    156: 
                    157:     node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
                    158:     if (!node) outofmem(__FILE__, "HTAcceptEncoding");
                    159:     HTList_addObject(list, (void*)node);
                    160: 
                    161:     node->atom = HTAtom_for(enc);
                    162:     node->quality = quality;
                    163: }
                    164: 
                    165: 
                    166: PUBLIC void HTAcceptLanguage ARGS3(HTList *,   list,
                    167:                                   char *,      lang,
                    168:                                   float,       quality)
                    169: {
                    170:     HTAcceptNode * node;
                    171: 
                    172:     if (!list || !lang || !*lang) return;
                    173: 
                    174:     node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
                    175:     if (!node) outofmem(__FILE__, "HTAcceptLanguage");
                    176: 
                    177:     HTList_addObject(list, (void*)node);
                    178:     node->atom = HTAtom_for(lang);
                    179:     node->quality = quality;
                    180: }
                    181: 
                    182: 
1.48      frystyk   183: PRIVATE BOOL wild_match ARGS2(HTAtom *,        tmplate,
1.17      luotonen  184:                              HTAtom *, actual)
                    185: {
                    186:     char *t, *a, *st, *sa;
                    187:     BOOL match = NO;
                    188: 
1.48      frystyk   189:     if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22      luotonen  190:        if (!strcmp(t, "*"))
                    191:            return YES;
1.17      luotonen  192: 
1.22      luotonen  193:        if (strchr(t, '*') &&
                    194:            (a = HTAtom_name(actual)) &&
                    195:            (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17      luotonen  196: 
1.22      luotonen  197:            *sa = 0;
                    198:            *st = 0;
                    199: 
                    200:            if ((*(st-1)=='*' &&
                    201:                 (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
                    202:                (*(st+1)=='*' && !strcasecomp(t,a)))
                    203:                match = YES;
                    204: 
                    205:            *sa = '/';
                    206:            *st = '/';
                    207:        }    
                    208:     }
1.23      luotonen  209:     return match;
1.17      luotonen  210: }
                    211: 
1.36      luotonen  212: /*
                    213:  * Added by takada@seraph.ntt.jp (94/04/08)
                    214:  */
1.48      frystyk   215: PRIVATE BOOL lang_match ARGS2(HTAtom *,        tmplate,
1.36      luotonen  216:                              HTAtom *, actual)
                    217: {
                    218:     char *t, *a, *st, *sa;
                    219:     BOOL match = NO;
                    220: 
1.48      frystyk   221:     if (tmplate && actual &&
                    222:        (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36      luotonen  223:        st = strchr(t, '_');
                    224:        sa = strchr(a, '_');
                    225:        if ((st != NULL) && (sa != NULL)) {
                    226:            if (!strcasecomp(t, a))
                    227:              match = YES;
                    228:            else
                    229:              match = NO;
                    230:        }
                    231:        else {
                    232:            if (st != NULL) *st = 0;
                    233:            if (sa != NULL) *sa = 0;
                    234:            if (!strcasecomp(t, a))
                    235:              match = YES;
                    236:            else
                    237:              match = NO;
                    238:            if (st != NULL) *st = '_';
                    239:            if (sa != NULL) *sa = '_';
                    240:        }
                    241:     }
                    242:     return match;
                    243: }
                    244: /* end of addition */
                    245: 
                    246: 
1.17      luotonen  247: 
                    248: PRIVATE float type_value ARGS2(HTAtom *,       content_type,
                    249:                               HTList *,        accepted)
                    250: {
                    251:     HTList * cur = accepted;
                    252:     HTPresentation * pres;
                    253:     HTPresentation * wild = NULL;
                    254: 
                    255:     if (!content_type || !accepted) return -1;
                    256: 
                    257:     while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    258:        if (pres->rep == content_type)
                    259:            return pres->quality;
                    260:        else if (wild_match(pres->rep, content_type))
                    261:            wild = pres;
                    262:     }
                    263:     if (wild) return wild->quality;
                    264:     else return -1;
                    265: }
                    266: 
                    267: 
                    268: PRIVATE float lang_value ARGS2(HTAtom *,       language,
                    269:                               HTList *,        accepted)
                    270: {
                    271:     HTList * cur = accepted;
                    272:     HTAcceptNode * node;
                    273:     HTAcceptNode * wild = NULL;
                    274: 
                    275:     if (!language || !accepted || HTList_isEmpty(accepted)) {
                    276:        return 0.1;
                    277:     }
                    278: 
                    279:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    280:        if (node->atom == language) {
                    281:            return node->quality;
                    282:        }
1.36      luotonen  283:        /*
                    284:         * patch by takada@seraph.ntt.jp (94/04/08)
                    285:         * the original line was
                    286:         * else if (wild_match(node->atom, language)) {
                    287:         * and the new line is
                    288:         */
                    289:        else if (lang_match(node->atom, language)) {
1.17      luotonen  290:            wild = node;
                    291:        }
                    292:     }
                    293: 
                    294:     if (wild) {
                    295:        return wild->quality;
                    296:     }
                    297:     else {
                    298:        return 0.1;
                    299:     }
                    300: }
                    301: 
                    302: 
                    303: PRIVATE float encoding_value ARGS2(HTAtom *,   encoding,
                    304:                                   HTList *,    accepted)
                    305: {
                    306:     HTList * cur = accepted;
                    307:     HTAcceptNode * node;
                    308:     HTAcceptNode * wild = NULL;
                    309:     char * e;
                    310: 
                    311:     if (!encoding || !accepted || HTList_isEmpty(accepted))
                    312:        return 1;
                    313: 
                    314:     e = HTAtom_name(encoding);
                    315:     if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
                    316:        return 1;
                    317: 
                    318:     while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
                    319:        if (node->atom == encoding)
                    320:            return node->quality;
                    321:        else if (wild_match(node->atom, encoding))
                    322:            wild = node;
                    323:     }
                    324:     if (wild) return wild->quality;
                    325:     else return 1;
                    326: }
                    327: 
                    328: 
                    329: PUBLIC BOOL HTRank ARGS4(HTList *, possibilities,
                    330:                         HTList *, accepted_content_types,
                    331:                         HTList *, accepted_languages,
                    332:                         HTList *, accepted_encodings)
                    333: {
                    334:     int accepted_cnt = 0;
                    335:     HTList * accepted;
                    336:     HTList * sorted;
                    337:     HTList * cur;
                    338:     HTContentDescription * d;
                    339: 
                    340:     if (!possibilities) return NO;
                    341: 
                    342:     accepted = HTList_new();
                    343:     cur = possibilities;
                    344:     while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
                    345:        float tv = type_value(d->content_type, accepted_content_types);
                    346:        float lv = lang_value(d->content_language, accepted_languages);
                    347:        float ev = encoding_value(d->content_encoding, accepted_encodings);
                    348: 
                    349:        if (tv > 0) {
                    350:            d->quality *= tv * lv * ev;
                    351:            HTList_addObject(accepted, d);
                    352:            accepted_cnt++;
                    353:        }
1.18      luotonen  354:        else {
                    355:            if (d->filename) free(d->filename);
                    356:            free(d);
                    357:        }
1.17      luotonen  358:     }
                    359: 
1.56.2.1! frystyk   360:     if (PROT_TRACE) fprintf(TDEST, "Ranking.....\n");
        !           361:     if (PROT_TRACE) fprintf(TDEST,
1.18      luotonen  362:           "\nRANK QUALITY CONTENT-TYPE         LANGUAGE ENCODING    FILE\n");
1.17      luotonen  363: 
                    364:     sorted = HTList_new();
                    365:     while (accepted_cnt-- > 0) {
                    366:        HTContentDescription * worst = NULL;
                    367:        cur = accepted;
                    368:        while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
                    369:            if (!worst || d->quality < worst->quality)
                    370:                worst = d;
                    371:        }
                    372:        if (worst) {
1.56.2.1! frystyk   373:            if (PROT_TRACE)
        !           374:                fprintf(TDEST, "%d.   %.4f  %-20.20s %-8.8s %-10.10s %s\n",
        !           375:                        accepted_cnt+1,
        !           376:                        worst->quality,
        !           377:                        (worst->content_type
1.17      luotonen  378:                         ? HTAtom_name(worst->content_type)      : "-"),
1.56.2.1! frystyk   379:                        (worst->content_language
1.17      luotonen  380:                         ? HTAtom_name(worst->content_language)  :"-"),
1.56.2.1! frystyk   381:                        (worst->content_encoding
1.17      luotonen  382:                         ? HTAtom_name(worst->content_encoding)  :"-"),
1.56.2.1! frystyk   383:                        (worst->filename
1.17      luotonen  384:                         ? worst->filename                       :"-"));
                    385:            HTList_removeObject(accepted, (void*)worst);
                    386:            HTList_addObject(sorted, (void*)worst);
                    387:        }
                    388:     }
1.56.2.1! frystyk   389:     if (PROT_TRACE) fprintf(TDEST, "\n");
1.17      luotonen  390:     HTList_delete(accepted);
                    391:     HTList_delete(possibilities->next);
                    392:     possibilities->next = sorted->next;
                    393:     sorted->next = NULL;
                    394:     HTList_delete(sorted);
                    395: 
                    396:     if (!HTList_isEmpty(possibilities)) return YES;
                    397:     else return NO;
                    398: }
                    399: 
                    400: 
                    401: 
                    402: 
                    403: 
1.13      timbl     404: /*                     Socket Input Buffering
                    405: **                     ----------------------
1.1       timbl     406: **
1.13      timbl     407: **     This code is used because one cannot in general open a
                    408: **     file descriptor for a socket.
                    409: **
1.1       timbl     410: **     The input file is read using the macro which can read from
1.13      timbl     411: **     a socket or a file, but this should not be used for files
                    412: **     as fopen() etc is more portable of course.
                    413: **
1.1       timbl     414: **     The input buffer size, if large will give greater efficiency and
                    415: **     release the server faster, and if small will save space on PCs etc.
                    416: */
                    417: 
                    418: 
                    419: /*     Set up the buffering
                    420: **
                    421: **     These routines are public because they are in fact needed by
                    422: **     many parsers, and on PCs and Macs we should not duplicate
                    423: **     the static buffer area.
                    424: */
1.56.2.1! frystyk   425: PUBLIC HTInputSocket * HTInputSocket_new ARGS1 (SOCKFD, file_number)
1.1       timbl     426: {
1.28      frystyk   427:     HTInputSocket *isoc = (HTInputSocket *)calloc(1, sizeof(*isoc));
1.13      timbl     428:     if (!isoc) outofmem(__FILE__, "HTInputSocket_new");
                    429:     isoc->input_file_number = file_number;
                    430:     isoc->input_pointer = isoc->input_limit = isoc->input_buffer;
                    431:     return isoc;
1.1       timbl     432: }
                    433: 
1.35      frystyk   434: /* This should return HT_INTERRUPTED if interrupted BUT the connection
                    435:    MUST not be closed */ 
                    436: PUBLIC int HTInputSocket_getCharacter ARGS1(HTInputSocket*, isoc)
1.1       timbl     437: {
1.35      frystyk   438:     int ch;
1.1       timbl     439:     do {
1.52      frystyk   440:        if (isoc->input_pointer >= isoc->input_limit) {
                    441:            int status = NETREAD(isoc->input_file_number,
                    442:                                 isoc->input_buffer, INPUT_BUFFER_SIZE);
1.1       timbl     443:            if (status <= 0) {
1.39      frystyk   444:                if (status == 0)
                    445:                    return EOF;
                    446:                if (status == HT_INTERRUPTED) {
                    447:                    if (TRACE)
1.56.2.1! frystyk   448:                        fprintf(TDEST, "Get Char.... Interrupted in HTInputSocket_getCharacter\n");
1.39      frystyk   449:                    return HT_INTERRUPTED;
                    450:                }
1.56.2.1! frystyk   451:                if (PROT_TRACE)
        !           452:                    fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
1.39      frystyk   453:                return EOF;     /* -1 is returned by UCX at end of HTTP link */
1.1       timbl     454:            }
1.35      frystyk   455:            isoc->input_pointer = isoc->input_buffer;
1.13      timbl     456:            isoc->input_limit = isoc->input_buffer + status;
1.1       timbl     457:        }
1.39      frystyk   458:        ch = (unsigned char) *isoc->input_pointer++;
                    459:     } while (ch == 13);                             /* Ignore ASCII carriage return */
1.1       timbl     460:     
                    461:     return FROMASCII(ch);
                    462: }
                    463: 
1.17      luotonen  464: PUBLIC void HTInputSocket_free ARGS1(HTInputSocket *, me)
1.13      timbl     465: {
                    466:     if (me) free(me);
                    467: }
                    468: 
                    469: 
1.16      luotonen  470: PUBLIC char * HTInputSocket_getBlock ARGS2(HTInputSocket*,     isoc,
                    471:                                           int *,               len)
                    472: {
                    473:     if (isoc->input_pointer >= isoc->input_limit) {
                    474:        int status = NETREAD(isoc->input_file_number,
                    475:                             isoc->input_buffer,
                    476:                             ((*len < INPUT_BUFFER_SIZE) ?
                    477:                              *len : INPUT_BUFFER_SIZE));
                    478:        if (status <= 0) {
                    479:            isoc->input_limit = isoc->input_buffer;
1.56.2.1! frystyk   480:            if (status < 0) {
        !           481:                if (PROT_TRACE)
        !           482:                    fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
        !           483:            }
1.16      luotonen  484:            *len = 0;
                    485:            return NULL;
                    486:        }
                    487:        else {
                    488:            *len = status;
                    489:            return isoc->input_buffer;
                    490:        }
                    491:     }
                    492:     else {
                    493:        char * ret = isoc->input_pointer;
                    494:        *len = isoc->input_limit - isoc->input_pointer;
                    495:        isoc->input_pointer = isoc->input_limit;
                    496:        return ret;
                    497:     }
                    498: }
                    499: 
                    500: 
1.15      luotonen  501: PRIVATE int fill_in_buffer ARGS1(HTInputSocket *, isoc)
                    502: {
                    503:     if (isoc) {
                    504:        int status;
                    505: 
                    506:        isoc->input_pointer = isoc->input_buffer;
                    507:        status = NETREAD(isoc->input_file_number,
                    508:                         isoc->input_buffer,
                    509:                         INPUT_BUFFER_SIZE);
                    510:        if (status <= 0) {
                    511:            isoc->input_limit = isoc->input_buffer;
1.56.2.1! frystyk   512:            if (status < 0) {
        !           513:                if (PROT_TRACE)
        !           514:                    fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
        !           515:            }
1.15      luotonen  516:        }
                    517:        else 
                    518:            isoc->input_limit = isoc->input_buffer + status;
                    519:        return status;
                    520:     }
                    521:     return -1;
                    522: }
                    523: 
                    524: 
                    525: PRIVATE void ascii_cat ARGS3(char **,  linep,
                    526:                             char *,    start,
                    527:                             char *,    end)
                    528: {
                    529:     if (linep && start && end && start <= end) {
                    530:        char *ptr;
                    531: 
                    532:        if (*linep) {
                    533:            int len = strlen(*linep);
                    534:            *linep = (char*)realloc(*linep, len + end-start + 1);
                    535:            ptr = *linep + len;
                    536:        }
                    537:        else {
                    538:            ptr = *linep = (char*)malloc(end-start + 1);
                    539:        }
                    540: 
                    541:        while (start < end) {
                    542:            *ptr = FROMASCII(*start);
                    543:            ptr++;
                    544:            start++;
                    545:        }
                    546:        *ptr = 0;
                    547:     }
                    548: }
                    549: 
                    550: 
                    551: PRIVATE char * get_some_line ARGS2(HTInputSocket *,    isoc,
                    552:                                   BOOL,                unfold)
                    553: {
                    554:     if (!isoc)
                    555:        return NULL;
                    556:     else {
                    557:        BOOL check_unfold = NO;
                    558:        int prev_cr = 0;
                    559:        char *start = isoc->input_pointer;
                    560:        char *cur = isoc->input_pointer;
                    561:        char * line = NULL;
                    562: 
                    563:        for(;;) {
                    564:            /*
                    565:            ** Get more if needed to complete line
                    566:            */
                    567:            if (cur >= isoc->input_limit) { /* Need more data */
                    568:                ascii_cat(&line, start, cur);
                    569:                if (fill_in_buffer(isoc) <= 0)
                    570:                    return line;
                    571:                start = cur = isoc->input_pointer;
                    572:            } /* if need more data */
                    573: 
                    574:            /*
                    575:            ** Find a line feed if there is one
                    576:            */
                    577:            for(; cur < isoc->input_limit; cur++) {
                    578:                char c = FROMASCII(*cur);
                    579:                if (!c) {
1.18      luotonen  580:                    if (line) free(line);       /* Leak fixed AL 6 Feb 94 */
1.15      luotonen  581:                    return NULL;        /* Panic! read a 0! */
                    582:                }
                    583:                if (check_unfold  &&  c != ' '  &&  c != '\t') {
                    584:                    return line;  /* Note: didn't update isoc->input_pointer */
                    585:                }
                    586:                else {
                    587:                    check_unfold = NO;
                    588:                }
                    589: 
                    590:                if (c=='\r') {
                    591:                    prev_cr = 1;
                    592:                }
                    593:                else {
                    594:                    if (c=='\n') {              /* Found a line feed */
                    595:                        ascii_cat(&line, start, cur-prev_cr);
                    596:                        start = isoc->input_pointer = cur+1;
                    597: 
1.44      frystyk   598:                        if (line && (int) strlen(line) > 0 && unfold) {
1.15      luotonen  599:                            check_unfold = YES;
                    600:                        }
                    601:                        else {
                    602:                            return line;
                    603:                        }
                    604:                    } /* if NL */
                    605:                    /* else just a regular character */
                    606:                    prev_cr = 0;
                    607:                } /* if not CR */
                    608:            } /* while characters in buffer remain */
                    609:        } /* until line read or end-of-file */
                    610:     } /* valid parameters to function */
                    611: }
                    612: 
1.43      frystyk   613: /* The returned string must be freed by the caller */
1.15      luotonen  614: PUBLIC char * HTInputSocket_getLine ARGS1(HTInputSocket *, isoc)
                    615: {
                    616:     return get_some_line(isoc, NO);
                    617: }
                    618: 
1.43      frystyk   619: /* The returned string must be freed by the caller */
1.15      luotonen  620: PUBLIC char * HTInputSocket_getUnfoldedLine ARGS1(HTInputSocket *, isoc)
                    621: {
                    622:     return get_some_line(isoc, YES);
                    623: }
                    624: 
                    625: 
1.33      luotonen  626: PRIVATE BOOL better_match ARGS2(HTFormat, f,
                    627:                                HTFormat, g)
                    628: {
                    629:     CONST char *p, *q;
                    630: 
                    631:     if (f && g  &&  (p = HTAtom_name(f))  &&  (q = HTAtom_name(g))) {
                    632:        int i,j;
                    633:        for(i=0 ; *p; p++) if (*p == '*') i++;
                    634:        for(j=0 ; *q; q++) if (*q == '*') j++;
                    635:        if (i < j) return YES;
                    636:     }
                    637:     return NO;
                    638: }
                    639: 
1.17      luotonen  640: 
1.2       timbl     641: /*             Create a filter stack
                    642: **             ---------------------
                    643: **
1.7       secret    644: **     If a wildcard match is made, a temporary HTPresentation
1.2       timbl     645: **     structure is made to hold the destination format while the
                    646: **     new stack is generated. This is just to pass the out format to
                    647: **     MIME so far.  Storing the format of a stream in the stream might
                    648: **     be a lot neater.
1.10      timbl     649: **
1.29      frystyk   650: **     The star/star format is special, in that if you can take
1.40      frystyk   651: **     that you can take anything.
                    652: **
                    653: **     On succes, request->error_block is set to YES so no more error
                    654: **     messages to the stream as the stream might be of any format.
1.2       timbl     655: */
1.52      frystyk   656: PUBLIC HTStream * HTStreamStack ARGS5(HTFormat,                rep_in,
                    657:                                      HTFormat,         rep_out,
                    658:                                      HTStream *,       output_stream,
1.34      luotonen  659:                                      HTRequest *,      request,
                    660:                                      BOOL,             guess)
1.2       timbl     661: {
1.14      timbl     662:     HTList * conversion[2];
                    663:     int which_list;
1.25      frystyk   664:     float best_quality = -1e30;                /* Pretty bad! */
1.29      frystyk   665:     HTPresentation *pres, *match, *best_match=0;
1.14      timbl     666:     
1.47      frystyk   667:     request->error_block = YES;                   /* No more error output to stream */
1.56.2.1! frystyk   668:     if (TRACE) fprintf(TDEST,
1.39      frystyk   669:        "StreamStack. Constructing stream stack for %s to %s\n",
1.10      timbl     670:        HTAtom_name(rep_in),    
1.2       timbl     671:        HTAtom_name(rep_out));
1.34      luotonen  672: 
                    673:     if (guess  &&  rep_in == WWW_UNKNOWN) {
1.56.2.1! frystyk   674:        if (PROT_TRACE) fprintf(TDEST, "Returning... guessing stream\n");
1.52      frystyk   675:        return HTGuess_new(request, NULL, rep_in, rep_out, output_stream);
1.34      luotonen  676:     }
                    677: 
1.47      frystyk   678:     if (rep_out == WWW_SOURCE || rep_out == rep_in) {
1.52      frystyk   679:        return output_stream;
1.47      frystyk   680:     }
1.2       timbl     681: 
1.14      timbl     682:     conversion[0] = request->conversions;
                    683:     conversion[1] = HTConversions;
1.17      luotonen  684: 
1.15      luotonen  685:     for(which_list = 0; which_list<2; which_list++) {
                    686:        HTList * cur = conversion[which_list];
                    687:        
                    688:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.25      frystyk   689:            if  ((pres->rep == rep_in || wild_match(pres->rep, rep_in)) &&
1.33      luotonen  690:                 (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
                    691:                if (!best_match ||
                    692:                    better_match(pres->rep, best_match->rep) ||
                    693:                    (!better_match(best_match->rep, pres->rep) &&
                    694:                     pres->quality > best_quality)) {
1.56.2.1! frystyk   695: #ifdef GOT_SYSTEM
        !           696:                    if (!pres->test_command||(system(pres->test_command)==0)){ 
1.49      howcome   697:                        if (TRACE && pres->test_command) 
1.56.2.1! frystyk   698:                            fprintf(TDEST, "HTStreamStack testing %s %d\n",pres->test_command,system(pres->test_command)); 
1.49      howcome   699:                        best_match = pres;
                    700:                        best_quality = pres->quality;
                    701:                    }
1.56.2.1! frystyk   702: #endif /* GOT_SYSTEM */
1.10      timbl     703:                }
                    704:            }
1.2       timbl     705:        }
                    706:     }
1.33      luotonen  707: 
1.29      frystyk   708:     match = best_match ? best_match : NULL;
                    709:     if (match) {
                    710:        if (match->rep == WWW_SOURCE) {
1.56.2.1! frystyk   711:            if (TRACE) fprintf(TDEST, "StreamStack. Don't know how to handle this, so put out %s to %s\n",
1.29      frystyk   712:                               HTAtom_name(match->rep), 
                    713:                               HTAtom_name(rep_out));
                    714:        }
1.52      frystyk   715:        return (*match->converter)(request, match->command, rep_in, rep_out,
                    716:                                   output_stream);
1.29      frystyk   717:     }
1.42      frystyk   718:     {
                    719:        char *msg = NULL;
                    720:        StrAllocCopy(msg, "Can't convert from ");
                    721:        StrAllocCat(msg, HTAtom_name(rep_in));
                    722:        StrAllocCat(msg, " to ");
                    723:        StrAllocCat(msg, HTAtom_name(rep_out));
                    724:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
                    725:                   (void *) msg, (int) strlen(msg), "HTStreamStack");
                    726:        free(msg);
                    727:     }
1.47      frystyk   728:     request->error_block = NO;          /* We didn't put up a stream anyway */
1.2       timbl     729:     return NULL;
                    730: }
                    731:        
                    732: 
                    733: /*             Find the cost of a filter stack
                    734: **             -------------------------------
                    735: **
                    736: **     Must return the cost of the same stack which StreamStack would set up.
                    737: **
                    738: ** On entry,
                    739: **     length  The size of the data to be converted
                    740: */
1.12      timbl     741: PUBLIC float HTStackValue ARGS5(
1.14      timbl     742:        HTList *,               theseConversions,
1.10      timbl     743:        HTFormat,               rep_in,
1.2       timbl     744:        HTFormat,               rep_out,
                    745:        float,                  initial_value,
                    746:        long int,               length)
                    747: {
1.14      timbl     748:     int which_list;
                    749:     HTList* conversion[2];
                    750:     
1.56.2.1! frystyk   751:     if (TRACE) fprintf(TDEST,
1.39      frystyk   752:        "StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
1.10      timbl     753:        HTAtom_name(rep_in),    initial_value,
1.2       timbl     754:        HTAtom_name(rep_out));
                    755:                
                    756:     if (rep_out == WWW_SOURCE ||
1.10      timbl     757:        rep_out == rep_in) return 0.0;
1.2       timbl     758: 
1.14      timbl     759:     conversion[0] = theseConversions;
                    760:     conversion[1] = HTConversions;
                    761:     
                    762:     for(which_list = 0; which_list<2; which_list++)
                    763:      if (conversion[which_list]) {
1.15      luotonen  764:         HTList * cur = conversion[which_list];
1.2       timbl     765:        HTPresentation * pres;
1.15      luotonen  766:        while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    767:            if (pres->rep == rep_in &&
1.17      luotonen  768:                (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.2       timbl     769:                float value = initial_value * pres->quality;
                    770:                if (HTMaxSecs != 0.0)
1.15      luotonen  771:                    value = value - (length*pres->secs_per_byte + pres->secs)
1.2       timbl     772:                                         /HTMaxSecs;
                    773:                return value;
                    774:            }
                    775:        }
                    776:     }
                    777:     
                    778:     return -1e30;              /* Really bad */
1.17      luotonen  779: }
                    780: 
                    781: 
1.2       timbl     782: 
1.1       timbl     783: 
1.2       timbl     784: /*     Push data from a socket down a stream
                    785: **     -------------------------------------
1.1       timbl     786: **
1.2       timbl     787: **   This routine is responsible for creating and PRESENTING any
1.1       timbl     788: **   graphic (or other) objects described by the file.
1.2       timbl     789: **
                    790: **   The file number given is assumed to be a TELNET stream ie containing
                    791: **   CRLF at the end of lines which need to be stripped to LF for unix
                    792: **   when the format is textual.
                    793: **
1.26      luotonen  794: **   RETURNS the number of bytes transferred.
                    795: **
1.1       timbl     796: */
1.26      luotonen  797: PUBLIC int HTCopy ARGS2(
1.56.2.1! frystyk   798:        SOCKFD,                 file_number,
1.2       timbl     799:        HTStream*,              sink)
1.1       timbl     800: {
1.2       timbl     801:     HTStreamClass targetClass;    
1.13      timbl     802:     HTInputSocket * isoc;
1.26      luotonen  803:     int cnt = 0;
                    804: 
1.5       timbl     805: /*     Push the data down the stream
1.2       timbl     806: **
                    807: */
                    808:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
1.13      timbl     809:     isoc = HTInputSocket_new(file_number);
1.2       timbl     810:     
                    811:     /* Push binary from socket down sink
1.10      timbl     812:     **
                    813:     **         This operation could be put into a main event loop
1.2       timbl     814:     */
                    815:     for(;;) {
                    816:        int status = NETREAD(
1.13      timbl     817:                file_number, isoc->input_buffer, INPUT_BUFFER_SIZE);
1.2       timbl     818:        if (status <= 0) {
                    819:            if (status == 0) break;
1.56.2.1! frystyk   820:            if (TRACE) fprintf(TDEST,
1.39      frystyk   821:                "Socket Copy. Read error, read returns %d with errno=%d\n",
1.56.2.1! frystyk   822:                status, socerrno);
1.2       timbl     823:            break;
                    824:        }
1.26      luotonen  825: 
1.8       timbl     826: #ifdef NOT_ASCII
                    827:        {
                    828:            char * p;
1.13      timbl     829:            for(p = isoc->input_buffer; p < isoc->input_buffer+status; p++) {
1.8       timbl     830:                *p = FROMASCII(*p);
                    831:            }
                    832:        }
                    833: #endif
                    834: 
1.13      timbl     835:        (*targetClass.put_block)(sink, isoc->input_buffer, status);
1.26      luotonen  836:        cnt += status;
1.2       timbl     837:     } /* next bufferload */
1.26      luotonen  838: 
1.13      timbl     839:     HTInputSocket_free(isoc);
1.26      luotonen  840: 
                    841:     return cnt;
1.2       timbl     842: }
                    843: 
1.1       timbl     844: 
1.7       secret    845: 
                    846: /*     Push data from a file pointer down a stream
                    847: **     -------------------------------------
                    848: **
                    849: **   This routine is responsible for creating and PRESENTING any
                    850: **   graphic (or other) objects described by the file.
                    851: **
                    852: **
                    853: */
                    854: PUBLIC void HTFileCopy ARGS2(
                    855:        FILE *,                 fp,
                    856:        HTStream*,              sink)
                    857: {
                    858:     HTStreamClass targetClass;    
1.13      timbl     859:     char input_buffer[INPUT_BUFFER_SIZE];
1.7       secret    860:     
                    861: /*     Push the data down the stream
                    862: **
                    863: */
                    864:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    865:     
                    866:     /* Push binary from socket down sink
                    867:     */
                    868:     for(;;) {
                    869:        int status = fread(
                    870:               input_buffer, 1, INPUT_BUFFER_SIZE, fp);
                    871:        if (status == 0) { /* EOF or error */
                    872:            if (ferror(fp) == 0) break;
1.56.2.1! frystyk   873:            if (TRACE) fprintf(TDEST,
1.39      frystyk   874:                "File Copy... Read error, read returns %d\n", ferror(fp));
1.7       secret    875:            break;
                    876:        }
                    877:        (*targetClass.put_block)(sink, input_buffer, status);
1.13      timbl     878:     } /* next bufferload */    
1.7       secret    879: }
                    880: 
                    881: 
                    882: 
                    883: 
1.2       timbl     884: /*     Push data from a socket down a stream STRIPPING CR
                    885: **     --------------------------------------------------
                    886: **
                    887: **   This routine is responsible for creating and PRESENTING any
1.8       timbl     888: **   graphic (or other) objects described by the socket.
1.2       timbl     889: **
                    890: **   The file number given is assumed to be a TELNET stream ie containing
                    891: **   CRLF at the end of lines which need to be stripped to LF for unix
                    892: **   when the format is textual.
1.37      frystyk   893: **     
                    894: **     Character handling is now of type int, Henrik, May 09-94
1.1       timbl     895: */
1.2       timbl     896: PUBLIC void HTCopyNoCR ARGS2(
1.56.2.1! frystyk   897:        SOCKFD,                 file_number,
1.2       timbl     898:        HTStream*,              sink)
                    899: {
1.13      timbl     900:     HTStreamClass targetClass;
                    901:     HTInputSocket * isoc;   
1.37      frystyk   902:     int ch;
1.1       timbl     903:     
1.2       timbl     904: /*     Push the data, ignoring CRLF, down the stream
                    905: **
                    906: */
                    907:     targetClass = *(sink->isa);        /* Copy pointers to procedures */
                    908: 
                    909: /*     Push text from telnet socket down sink
                    910: **
                    911: **     @@@@@ To push strings could be faster? (especially is we
                    912: **     cheat and don't ignore CR! :-}
                    913: */  
1.13      timbl     914:     isoc = HTInputSocket_new(file_number);
1.37      frystyk   915:     while ((ch = HTInputSocket_getCharacter(isoc)) >= 0)
                    916:        (*targetClass.put_character)(sink, ch);
1.13      timbl     917:     HTInputSocket_free(isoc);
1.2       timbl     918: }
1.1       timbl     919: 
1.2       timbl     920: 
                    921: /*     Parse a socket given format and file number
                    922: **
                    923: **   This routine is responsible for creating and PRESENTING any
                    924: **   graphic (or other) objects described by the file.
                    925: **
                    926: **   The file number given is assumed to be a TELNET stream ie containing
                    927: **   CRLF at the end of lines which need to be stripped to LF for unix
                    928: **   when the format is textual.
                    929: **
1.42      frystyk   930: **     Returns <0 on error, HT_LOADED on success.
1.2       timbl     931: */
1.14      timbl     932: 
1.46      frystyk   933: /* The parameter to this function and HTParsefile should be HTRequest */
                    934: 
1.12      timbl     935: PUBLIC int HTParseSocket ARGS3(
1.10      timbl     936:        HTFormat,               rep_in,
1.56.2.1! frystyk   937:        SOCKFD,                 file_number,
1.12      timbl     938:        HTRequest *,            request)
1.2       timbl     939: {
                    940:     HTStream * stream;
                    941:     HTStreamClass targetClass;    
1.1       timbl     942: 
1.40      frystyk   943:     if (request->error_stack) {
1.56.2.1! frystyk   944:        if (TRACE) fprintf(TDEST, "ParseSocket. Called whith non-empty error stack, so I return right away!\n");
1.40      frystyk   945:        return -1;
                    946:     }
                    947: 
1.42      frystyk   948:     /* Set up stream stack */
1.52      frystyk   949:     if ((stream = HTStreamStack(rep_in, request->output_format,
                    950:                                request->output_stream,
                    951:                                request, YES)) == NULL)
1.42      frystyk   952:        return -1;
1.1       timbl     953:     
1.3       timbl     954: /*     Push the data, ignoring CRLF if necessary, down the stream
                    955: **
1.2       timbl     956: **
1.3       timbl     957: **   @@  Bug:  This decision ought to be made based on "encoding"
1.9       timbl     958: **   rather than on format.  @@@  When we handle encoding.
1.3       timbl     959: **   The current method smells anyway.
1.2       timbl     960: */
                    961:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
1.52      frystyk   962:     if (rep_in == WWW_BINARY || rep_in == WWW_UNKNOWN
1.26      luotonen  963:        || (request->content_encoding &&
                    964:            request->content_encoding != HTAtom_for("8bit") &&
                    965:            request->content_encoding != HTAtom_for("7bit"))
1.10      timbl     966:         || strstr(HTAtom_name(rep_in), "image/")
                    967:        || strstr(HTAtom_name(rep_in), "video/")) { /* @@@@@@ */
1.29      frystyk   968:        HTCopy(file_number, stream);
1.52      frystyk   969:     } else
1.2       timbl     970:         HTCopyNoCR(file_number, stream);
1.45      duns      971:     (*targetClass._free)(stream);
1.7       secret    972:     
                    973:     return HT_LOADED;
                    974: }
                    975: 
                    976: 
                    977: 
                    978: /*     Parse a file given format and file pointer
                    979: **
                    980: **   This routine is responsible for creating and PRESENTING any
                    981: **   graphic (or other) objects described by the file.
                    982: **
                    983: **   The file number given is assumed to be a TELNET stream ie containing
1.10      timbl     984: **   CRLF at the end of lines which need to be stripped to \n for unix
1.7       secret    985: **   when the format is textual.
                    986: **
                    987: */
1.12      timbl     988: PUBLIC int HTParseFile ARGS3(
1.10      timbl     989:        HTFormat,               rep_in,
1.7       secret    990:        FILE *,                 fp,
1.12      timbl     991:        HTRequest *,            request)
1.7       secret    992: {
                    993:     HTStream * stream;
                    994:     HTStreamClass targetClass;    
1.40      frystyk   995: 
                    996:     if (request->error_stack) {
1.56.2.1! frystyk   997:        if (TRACE) fprintf(TDEST, "ParseFile... Called whith non-empty error stack, so I return right away!\n");
1.40      frystyk   998:        return -1;
                    999:     }
1.7       secret   1000: 
1.42      frystyk  1001:     /* Set up stream stack */
1.52      frystyk  1002:     if ((stream = HTStreamStack(rep_in, request->output_format,
                   1003:                                request->output_stream, request, YES)) == NULL)
1.42      frystyk  1004:        return -1;
1.7       secret   1005:     
1.9       timbl    1006: /*     Push the data down the stream
1.7       secret   1007: **
                   1008: **
                   1009: **   @@  Bug:  This decision ought to be made based on "encoding"
1.10      timbl    1010: **   rather than on content-type.  @@@  When we handle encoding.
1.7       secret   1011: **   The current method smells anyway.
                   1012: */
                   1013:     targetClass = *(stream->isa);      /* Copy pointers to procedures */
                   1014:     HTFileCopy(fp, stream);
1.45      duns     1015:     (*targetClass._free)(stream);
1.1       timbl    1016:     
1.2       timbl    1017:     return HT_LOADED;
1.1       timbl    1018: }
1.2       timbl    1019: 
1.10      timbl    1020: 
                   1021: /*     Converter stream: Network Telnet to internal character text
                   1022: **     -----------------------------------------------------------
                   1023: **
1.52      frystyk  1024: **     The input is assumed to be in local representation with lines
                   1025: **     delimited by (CR,LF) pairs in the local representation.
                   1026: **     The (CR,LF) sequenc when found is changed to a '\n' character,
                   1027: **     the internal C representation of a new line.
1.10      timbl    1028: */
1.52      frystyk  1029: PRIVATE void NetToText_put_character ARGS2(HTStream *, me, char, c)
1.10      timbl    1030: {
                   1031:     if (me->had_cr) {
                   1032:         if (c==LF) {
1.52      frystyk  1033:            me->sink->isa->put_character(me->sink, '\n');         /* Newline */
1.10      timbl    1034:            me->had_cr = NO;
                   1035:            return;
                   1036:         } else {
1.52      frystyk  1037:            me->sink->isa->put_character(me->sink, CR);          /* leftover */
1.10      timbl    1038:        }
                   1039:     }
                   1040:     me->had_cr = (c==CR);
                   1041:     if (!me->had_cr)
1.52      frystyk  1042:        me->sink->isa->put_character(me->sink, c);                 /* normal */
1.10      timbl    1043: }
                   1044: 
1.11      timbl    1045: PRIVATE void NetToText_put_string ARGS2(HTStream *, me, CONST char *, s)
1.52      frystyk  1046: {    
                   1047:     CONST char *p=s;
                   1048:     while (*p) {
                   1049:        if (me->had_cr) {
                   1050:            if (*p==LF) {
                   1051:                me->sink->isa->put_character(me->sink, '\n');     /* Newline */
                   1052:                s++;
                   1053:            } else
                   1054:                me->sink->isa->put_character(me->sink, CR);      /* leftover */
                   1055:        }
                   1056:        me->had_cr = (*p==CR);
                   1057:        if (me->had_cr) {
                   1058:            me->sink->isa->put_block(me->sink, s, p-s);
                   1059:            s=p+1;
                   1060:        }
                   1061:        p++;
                   1062:     }
                   1063:     if (p-s)
                   1064:        me->sink->isa->put_block(me->sink, s, p-s);
1.10      timbl    1065: }
                   1066: 
1.52      frystyk  1067: 
1.11      timbl    1068: PRIVATE void NetToText_put_block ARGS3(HTStream *, me, CONST char*, s, int, l)
1.10      timbl    1069: {
1.52      frystyk  1070:     CONST char *p=s;
                   1071:     while (l-- > 0) {
                   1072:        if (me->had_cr) {
                   1073:            if (*p==LF) {
                   1074:                me->sink->isa->put_character(me->sink, '\n');     /* Newline */
                   1075:                s++;
                   1076:            } else
                   1077:                me->sink->isa->put_character(me->sink, CR);      /* leftover */
                   1078:        }
                   1079:        me->had_cr = (*p==CR);
                   1080:        if (me->had_cr) {
                   1081:            me->sink->isa->put_block(me->sink, s, p-s);
                   1082:            s=p+1;
                   1083:        }
                   1084:        p++;
                   1085:     }
                   1086:     if (p-s)
                   1087:        me->sink->isa->put_block(me->sink, s, p-s);
1.10      timbl    1088: }
                   1089: 
1.52      frystyk  1090: PRIVATE int NetToText_free ARGS1(HTStream *, me)
1.10      timbl    1091: {
1.45      duns     1092:     me->sink->isa->_free(me->sink);            /* Close rest of pipe */
1.10      timbl    1093:     free(me);
1.52      frystyk  1094:     return 0;
1.10      timbl    1095: }
                   1096: 
1.52      frystyk  1097: PRIVATE int NetToText_abort ARGS2(HTStream *, me, HTError, e)
1.10      timbl    1098: {
                   1099:     me->sink->isa->abort(me->sink,e);          /* Abort rest of pipe */
                   1100:     free(me);
1.52      frystyk  1101:     return 0;
1.10      timbl    1102: }
                   1103: 
                   1104: PRIVATE HTStreamClass NetToTextClass = {
                   1105:     "NetToText",
                   1106:     NetToText_free,
                   1107:     NetToText_abort,
                   1108:     NetToText_put_character,
                   1109:     NetToText_put_string,
                   1110:     NetToText_put_block
                   1111: };
                   1112: 
                   1113: PUBLIC HTStream * HTNetToText ARGS1(HTStream *, sink)
                   1114: {
1.52      frystyk  1115:     HTStream* me = (HTStream *) calloc(1, sizeof(*me));
1.10      timbl    1116:     if (me == NULL) outofmem(__FILE__, "NetToText");
                   1117:     me->isa = &NetToTextClass;
                   1118:     
                   1119:     me->had_cr = NO;
                   1120:     me->sink = sink;
                   1121:     return me;
                   1122: }
1.52      frystyk  1123: 
                   1124: /* ------------------------------------------------------------------------- */
                   1125: /* MULTI THREADED IMPLEMENTATIONS                                           */
                   1126: /* ------------------------------------------------------------------------- */
                   1127: 
                   1128: /*     Push data from a socket down a stream
                   1129: **     -------------------------------------
                   1130: **
                   1131: **   This routine is responsible for creating and PRESENTING any
                   1132: **   graphic (or other) objects described by the file.
                   1133: **
                   1134: **
                   1135: ** Returns      HT_LOADED      if finished reading
                   1136: **             EOF             if error,
                   1137: **             HT_INTERRUPTED  if interrupted
                   1138: **                     HT_WOULD_BLOCK  if read would block
                   1139: */
                   1140: PUBLIC int HTInputSocket_read ARGS2(HTInputSocket *, isoc, HTStream *, target)
                   1141: {
                   1142:     int b_read;
                   1143: 
1.56.2.1! frystyk  1144:     if (!isoc || isoc->input_file_number==INVSOC) {
        !          1145:        if (PROT_TRACE) fprintf(TDEST, "Read Socket. Bad argument\n");
1.52      frystyk  1146:        return EOF;
                   1147:     }
                   1148: 
                   1149:     /* Push binary from socket down sink */
                   1150:     for(;;) {
                   1151:        if (HTThreadIntr(isoc->input_file_number))            /* Interrupted */
                   1152:            return HT_INTERRUPTED;
                   1153:        if ((b_read = NETREAD(isoc->input_file_number, isoc->input_buffer,
                   1154:                              INPUT_BUFFER_SIZE)) < 0) {
                   1155: #ifdef EAGAIN
1.56.2.1! frystyk  1156:            if (socerrno==EAGAIN || socerrno==EWOULDBLOCK)    /* POSIX, SVR4 */
1.52      frystyk  1157: #else
1.56.2.1! frystyk  1158:            if (socerrno == EWOULDBLOCK)                              /* BSD */
1.52      frystyk  1159: #endif
                   1160:            {
                   1161:                if (THD_TRACE)
1.56.2.1! frystyk  1162:                    fprintf(TDEST, "Read Socket. WOULD BLOCK soc %d\n",
1.52      frystyk  1163:                            isoc->input_file_number);
                   1164:                HTThreadState(isoc->input_file_number, THD_SET_READ);
                   1165:                return HT_WOULD_BLOCK;
                   1166:            } else {                                 /* We have a real error */
                   1167:                if (PROT_TRACE)
1.56.2.1! frystyk  1168:                    fprintf(TDEST, "Read Socket. READ ERROR %d\n", socerrno);
1.52      frystyk  1169:                return EOF;
                   1170:            }
                   1171:        } else if (!b_read) {
                   1172:            HTThreadState(isoc->input_file_number, THD_CLR_READ);
                   1173:            return HT_LOADED;
                   1174:        }
                   1175: 
                   1176: #ifdef NOT_ASCII
                   1177:        isoc->input_limit = isoc->input_buffer + b_read;
                   1178:        {
                   1179:            char *p;
                   1180:            for(p = isoc->input_buffer; p < isoc->input_limit; p++)
                   1181:                *p = FROMASCII(*p);
                   1182:        }
                   1183: #endif
                   1184: 
                   1185:        /* This is based on the assumption that we actually get rid of ALL
                   1186:           the bytes we have read. Maybe more feedback! */
1.54      frystyk  1187:        if (PROT_TRACE)
1.56.2.1! frystyk  1188:            fprintf(TDEST, "Read Socket. %d bytes read\n", b_read);
1.52      frystyk  1189:        (*target->isa->put_block)(target, isoc->input_buffer, b_read);
                   1190:        isoc->input_pointer += b_read;
                   1191:     }
                   1192: }

Webmaster