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

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

Webmaster