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

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

Webmaster