Annotation of libwww/Library/src/HTDialog.c, revision 2.23

2.1       frystyk     1: /*                                                                  HTDialog.c
                      2: **     MESSAGES AND DIALOGS
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.23    ! frystyk     6: **     @(#) $Id: HTDialog.c,v 2.22 1996/08/19 18:30:21 frystyk Exp $
2.1       frystyk     7: **
                      8: **     This module provides a default implementation of the application part
                      9: **     of the Message and Dialog part or the Library. You do not have to do
                     10: **     it like this - you can use exactly the model for mapping codes into
                     11: **     messages as you like
                     12: **
                     13: ** Authors
                     14: **     HFN     Henrik Frystyk
                     15: */
                     16: 
                     17: /* Library include files */
                     18: #include "WWWLib.h"
                     19: #include "WWWApp.h"
2.6       frystyk    20: #include "WWWHTTP.h"
2.1       frystyk    21: #include "HTDialog.h"                                   /* Implemented here */
                     22: 
                     23: /*
                     24: ** Dialog Messages
                     25: */
2.18      frystyk    26: PRIVATE const char * HTDialogs[HT_MSG_ELEMENTS] = {
2.1       frystyk    27:     "Please enter username:",
2.20      frystyk    28:     "Please enter username for proxy authentication:",
2.21      frystyk    29:     "Please enter username for this FTP server:",
2.1       frystyk    30:     "Password:",
                     31:     "Please give name of file to save in:",
                     32:     "Plase enter account:",
2.19      frystyk    33:     "You might not be allowed to use this method here, continue?",
2.1       frystyk    34:     "Location has moved, continue?",
2.17      frystyk    35:     "A new set of rules is to be added to your setup - continue?",
                     36:     "This file already exists - replace existing file?",
2.18      frystyk    37:     "Authentication failed - retry?",
2.19      frystyk    38:     "Proxy authentication failed - retry?",
2.18      frystyk    39:     "This method has already been performed - repeat operation?",
                     40:     "This document is very big - continue operation?",
                     41:     "The source document for this operation has moved - continue operation with new location?",
                     42:     "The destination document for this operation has moved - continue operation with new location?",
2.19      frystyk    43:     "A redirection may change the behavior of this method - proceed anyway?"
2.1       frystyk    44: };
                     45: 
                     46: /*
                     47: ** All errors that are not strictly HTTP errors but originates from, e.g., 
                     48: ** the FTP protocol all have element numbers > HTERR_HTTP_CODES_END, i.e.,
                     49: ** they should be placed after the blank line
                     50: */
                     51: typedef struct _HTErrorMessage {
                     52:     int        code;                   /* Error number */
                     53:     char *     msg;                    /* Short explanation */
                     54:     char *     url;                    /* Explaning URL */
                     55: } HTErrorMessage;
                     56: 
                     57: PRIVATE HTErrorMessage HTErrors[HTERR_ELEMENTS] = {
                     58: 
                     59: /*    CODE  ERROR MESSAGE                              ERROR URL */
                     60: 
2.15      frystyk    61:     { 100, "Continue",                                         "information" },
                     62:     { 101, "Switching Protocols",                      "information" },
                     63:     { 200, "OK",                                       "success" },
                     64:     { 201, "Created",                                  "success" },
                     65:     { 202, "Accepted",                                         "success" },
                     66:     { 203, "Non-authoritative Information",            "success" },
                     67:     { 204, "No Content",                               "success" },
                     68:     { 205, "Reset Content",                            "success" },
                     69:     { 206, "Partial Content",                          "success" },
                     70:     { 300, "Multiple Choices",                         "redirection" },
                     71:     { 301, "Moved Permanently",                                "redirection" },
                     72:     { 302, "Moved Temporarily",                        "redirection" },
                     73:     { 303, "See Other",                                        "redirection" },
                     74:     { 304, "Not Modified",                             "redirection" },
                     75:     { 305, "Use Proxy",                                        "redirection" },
                     76:     { 400, "Bad Request",                              "client_error" },
                     77:     { 401, "Unauthorized",                             "client_error" },
                     78:     { 402, "Payment Required",                                 "client_error" },
                     79:     { 403, "Forbidden",                                "client_error" },
                     80:     { 404, "Not Found",                                        "client_error" },
                     81:     { 405, "Method Not Allowed",                       "client_error" },
                     82:     { 406, "Not Acceptable",                           "client_error" },
                     83:     { 407, "Proxy Authentication Required",            "client_error" },
                     84:     { 408, "Request Timeout",                          "client_error" },
                     85:     { 409, "Conflict",                                 "client_error" },
                     86:     { 410, "Gone",                                     "client_error" },
                     87:     { 411, "Length Required",                          "client_error" },
                     88:     { 412, "Precondition Failed",                      "client_error" },
                     89:     { 413, "Request Entity Too Large",                 "client_error" },
                     90:     { 414, "Request-URI Too Large",                    "client_error" },
                     91:     { 415, "Unsupported Media Type",                   "client_error" },
                     92:     { 500, "Internal Server Error",                    "server_error" },
                     93:     { 501, "Not Implemented",                          "server_error" },
                     94:     { 502, "Bad Gateway",                              "server_error" },
                     95:     { 503, "Service Unavailable",                      "server_error" },
                     96:     { 504, "Gateway Timeout",                          "server_error" },
                     97:     { 505, "HTTP Version not supported",               "server_error" },
                     98: 
                     99:     /* Cache Warnings */
                    100:     { 10,  "Response is Stale",                                "cache" },
                    101:     { 11,  "Revalidation Failed",                      "cache" },
                    102:     { 12,  "Disconnected Opeartion",                   "cache" },
                    103:     { 13,  "Heuristic Expiration",                     "cache" },
                    104:     { 14,  "Transformation Applied",                   "cache" },
                    105:     { 99,  "Cache warning",                            "cache" },
                    106: 
                    107:     /* Non-HTTP Error codes and warnings */
                    108:     { 0,   "Can't locate remote host",                         "internal" },
                    109:     { 0,   "No host name found",                       "internal" },
                    110:     { 0,   "No file name found or file not accessible", "internal" },
                    111:     { 0,   "FTP-server replies",                       "internal" },
                    112:     { 0,   "FTP-server doesn't reply",                         "internal" },
                    113:     { 0,   "Server timed out",                                 "internal" },
                    114:     { 0,   "Gopher-server replies",                    "internal" },
                    115:     { 0,   "Data transfer interrupted",                "internal" },
                    116:     { 0,   "Connection establishment interrupted",     "internal" },
                    117:     { 0,   "CSO-server replies",                       "internal" },
                    118:     { 0,   "This is probably a HTTP server 0.9 or less","internal" },
                    119:     { 0,   "Bad, Incomplete, or Unknown Response",     "internal" },
                    120:     { 0,   "Unknown access authentication scheme",     "internal" },
                    121:     { 0,   "News-server replies",                      "internal" },
                    122:     { 0,   "Trying `ftp://' instead of `file://'",     "internal" },
                    123:     { 0,   "Too many redirections",                    "internal" },
2.16      frystyk   124:     { 0,   "Method not suited for automatic redirection","internal" },
2.15      frystyk   125:     { 0,   "Premature End Of File",                    "internal" },
                    126:     { 0,   "Response from WAIS Server too Large - Extra lines ignored","internal"},
                    127:     { 0,   "WAIS-server doesn't return any data",      "internal" },
                    128:     { 0,   "Can't connect to WAIS-server",             "internal" },
                    129:     { 0,   "System replies",                           "internal" },
                    130:     { 0,   "Wrong or unknown access scheme",           "internal" },
                    131:     { 0,   "Access scheme not allowed in this context",        "internal" },
2.23    ! frystyk   132:     { 0,   "When you are connected, you can log in",   "internal" },
        !           133:     { 0,   "This version has expired and will be automatically reloaded", "internal" }
2.1       frystyk   134: };
                    135: 
                    136: /* ------------------------------------------------------------------------- */
                    137: 
                    138: PUBLIC BOOL HTProgress (HTRequest * request, HTAlertOpcode op,
2.10      frystyk   139:                        int msgnum, const char * dfault, void * input,
2.1       frystyk   140:                        HTAlertPar * reply)
                    141: {
2.19      frystyk   142:     if (!request || HTRequest_internal(request)) return NO;
2.1       frystyk   143:     switch (op) {
                    144:       case HT_PROG_DNS:
2.9       frystyk   145:        HTTrace("Looking up %s\n", input ? (char *) input : "");
2.1       frystyk   146:        break;
                    147: 
                    148:       case HT_PROG_CONNECT:
2.9       frystyk   149:        HTTrace("Contacting %s\n", input ? (char *) input : "");
2.1       frystyk   150:        break;
                    151: 
                    152:       case HT_PROG_ACCEPT:
2.8       eric      153:        HTTrace("Waiting for connection...\n");
2.1       frystyk   154:        break;
                    155: 
                    156:       case HT_PROG_READ:
                    157:        {
                    158:            long cl = HTAnchor_length(HTRequest_anchor(request));
                    159:            if (cl > 0) {
                    160:                long b_read = HTRequest_bytesRead(request);
                    161:                double pro = (double) b_read/cl*100;
                    162:                char buf[10];
                    163:                HTNumToStr((unsigned long) cl, buf, 10);
2.8       eric      164:                HTTrace("Read (%d%% of %s)\n", (int) pro, buf);
2.1       frystyk   165:            } else
2.8       eric      166:                HTTrace("Reading...\n");
2.1       frystyk   167:        }
                    168:        break;
                    169: 
                    170:       case HT_PROG_WRITE:
2.4       frystyk   171:        if (HTRequest_isPostWeb(request)) {
                    172:            HTParentAnchor *anchor=HTRequest_anchor(HTRequest_source(request));
                    173:            long cl = HTAnchor_length(anchor);
                    174:            if (cl > 0) {
                    175:                long b_write = HTRequest_bytesWritten(request);
                    176:                double pro = (double) b_write/cl*100;
                    177:                char buf[10];
                    178:                HTNumToStr((unsigned long) cl, buf, 10);
2.8       eric      179:                HTTrace("Written (%d%% of %s)\n", (int) pro, buf);
2.4       frystyk   180:            } else
2.8       eric      181:                HTTrace("Writing...\n");
2.4       frystyk   182:        }
2.1       frystyk   183:        break;
                    184: 
                    185:       case HT_PROG_DONE:
2.22      frystyk   186:        HTTrace("Connection closed\n");
2.1       frystyk   187:        break;
                    188: 
                    189:       case HT_PROG_WAIT:
2.12      frystyk   190:        HTTrace("Waiting for free socket...\n");
2.1       frystyk   191:        break;
                    192: 
                    193:       default:
2.8       eric      194:        HTTrace("UNKNOWN PROGRESS STATE\n");
2.1       frystyk   195:        break;
                    196:     }
                    197:     return YES;
                    198: }
                    199: 
                    200: PUBLIC BOOL HTConfirm (HTRequest * request, HTAlertOpcode op,
2.10      frystyk   201:                       int msgnum, const char * dfault, void * input,
2.1       frystyk   202:                       HTAlertPar * reply)
                    203: {
                    204:     char response[4];  /* One more for terminating NULL -- AL */
2.8       eric      205:     HTTrace("%s", HTDialogs[msgnum]);
                    206:     if (input) HTTrace(" (%s)", (char *) input);
                    207:     HTTrace(" (y/n) ");
2.1       frystyk   208: #ifndef NO_STDIO
2.2       frystyk   209:     if (fgets(response, 4, stdin))                /* get reply, max 3 chars */
2.1       frystyk   210: #endif
2.2       frystyk   211:     {
2.1       frystyk   212:        char *ptr = response;
                    213:        while (*ptr) {
                    214:            if (*ptr == '\n') {
                    215:                *ptr = '\0';
                    216:                break;
                    217:            }
                    218:            *ptr = TOUPPER(*ptr);
                    219:            ptr++;
                    220:        }
                    221:        return (!strcmp(response, "YES") || !strcmp(response, "Y")) ? YES : NO;
                    222:     }
                    223:     return NO;
                    224: }
                    225: 
                    226: /*     Prompt for answer and get text back. Reply text is either NULL on
2.10      frystyk   227: **     error or a dynamic string which the caller must HT_FREE.
2.1       frystyk   228: */
                    229: PUBLIC BOOL HTPrompt (HTRequest * request, HTAlertOpcode op,
2.10      frystyk   230:                      int msgnum, const char * dfault, void * input,
2.1       frystyk   231:                      HTAlertPar * reply)
                    232: {
2.8       eric      233:     HTTrace("%s ", HTDialogs[msgnum]);
                    234:     if (input) HTTrace(" (%s) ", (char *) input);
                    235:     if (dfault) HTTrace("(RETURN for [%s]) ", (char *) dfault);
2.1       frystyk   236:     if (reply && msgnum>=0) {
                    237: #ifndef NO_STDIO
2.5       frystyk   238:         char buffer[200];
2.1       frystyk   239:        if (!fgets(buffer, 200, stdin)) return NO;
                    240:        buffer[strlen(buffer)-1] = '\0';                /* Overwrite newline */
                    241:        if (*buffer)
                    242:            HTAlert_setReplyMessage(reply, buffer);
                    243:        else if (dfault)
                    244:            HTAlert_setReplyMessage(reply, (char *) dfault);
                    245:        else
                    246:            return NO;
                    247:        return YES;
                    248: #endif
                    249:     }
                    250:     return NO;
                    251: }
                    252: 
                    253: /*     Prompt for password without echoing the reply. Reply text is
2.10      frystyk   254: **     either NULL on error or a dynamic string which the caller must HT_FREE.
2.1       frystyk   255: */
                    256: PUBLIC BOOL HTPromptPassword (HTRequest * request, HTAlertOpcode op,
2.10      frystyk   257:                              int msgnum, const char * dfault, void * input,
2.1       frystyk   258:                              HTAlertPar * reply)
                    259: {
                    260:     if (reply && msgnum>=0) {
2.10      frystyk   261: #ifdef HAVE_GETPASS
2.1       frystyk   262:        char * pw = (char *) getpass(HTDialogs[msgnum]);
2.2       frystyk   263:        if (pw) HTAlert_setReplySecret(reply, pw);
2.1       frystyk   264:        return YES;
2.10      frystyk   265: #else
2.11      eric      266:        return NO;      /* needed for WWW_MSWINDOWS */
2.10      frystyk   267: #endif /* HAVE_GETPASS */
2.1       frystyk   268:     }
                    269:     return NO;
                    270: }
                    271: 
                    272: /*     Username and password
                    273: **     ---------------------
                    274: **     Prompt Username and password as an atomic operation
                    275: */
                    276: PUBLIC BOOL HTPromptUsernameAndPassword (HTRequest * request, HTAlertOpcode op,
2.10      frystyk   277:                                         int msgnum, const char * dfault,
2.1       frystyk   278:                                         void * input, HTAlertPar * reply)
                    279: {
2.21      frystyk   280:     BOOL status = HTPrompt(request, op, msgnum, dfault, input, reply);
2.1       frystyk   281:     return status ?
                    282:        HTPromptPassword(request, op, HT_MSG_PW, dfault, input, reply) : NO;
                    283: }
                    284: 
                    285: /*     HTError_print
                    286: **     -------------
                    287: **     Default function that creates an error message using HTAlert() to
                    288: **     put out the contents of the error_stack messages. Furthermore, the
                    289: **     error_info structure contains a name of a help file that might be put
                    290: **     up as a link. This file can then be multi-linguistic.
                    291: */
                    292: PUBLIC BOOL HTError_print (HTRequest * request, HTAlertOpcode op,
2.10      frystyk   293:                           int msgnum, const char * dfault, void * input,
2.1       frystyk   294:                           HTAlertPar * reply)
                    295: {
                    296:     HTList *cur = (HTList *) input;
                    297:     HTError *pres;
                    298:     HTErrorShow showmask = HTError_show();
                    299:     HTChunk *msg = NULL;
                    300:     int code;
2.8       eric      301:     if (WWWTRACE) HTTrace("HTError..... Generating message\n");
2.1       frystyk   302:     if (!request || !cur) return NO;
                    303:     while ((pres = (HTError *) HTList_nextObject(cur))) {
                    304:        int index = HTError_index(pres);
                    305:        if (HTError_doShow(pres)) {
                    306:            if (!msg) {
                    307:                HTSeverity severity = HTError_severity(pres);
2.3       frystyk   308:                msg = HTChunk_new(128);
2.1       frystyk   309:                if (severity == ERR_WARN)
2.3       frystyk   310:                    HTChunk_puts(msg, "Warning: ");
2.1       frystyk   311:                else if (severity == ERR_NON_FATAL)
2.3       frystyk   312:                    HTChunk_puts(msg, "Non Fatal Error: ");
2.1       frystyk   313:                else if (severity == ERR_FATAL)
2.3       frystyk   314:                    HTChunk_puts(msg, "Fatal Error: ");
2.1       frystyk   315:                else if (severity == ERR_INFO)
2.3       frystyk   316:                    HTChunk_puts(msg, "Information: ");
2.1       frystyk   317:                else {
                    318:                    if (WWWTRACE)
2.8       eric      319:                        HTTrace("HTError..... Unknown Classification of Error (%d)...\n", severity);
2.3       frystyk   320:                    HTChunk_delete(msg);
2.1       frystyk   321:                    return NO;
                    322:                }
                    323: 
                    324:                /* Error number */
                    325:                if ((code = HTErrors[index].code) > 0) {
                    326:                    char buf[10];
                    327:                    sprintf(buf, "%d ", code);
2.3       frystyk   328:                    HTChunk_puts(msg, buf);
2.1       frystyk   329:                }
                    330:            } else
2.3       frystyk   331:                HTChunk_puts(msg, "\nReason: ");
                    332:            HTChunk_puts(msg, HTErrors[index].msg);         /* Error message */
2.1       frystyk   333: 
                    334:            if (showmask & HT_ERR_SHOW_PARS) {           /* Error parameters */
                    335:                int length;
                    336:                int cnt;                
                    337:                char *pars = (char *) HTError_parameter(pres, &length);
                    338:                if (length && pars) {
2.3       frystyk   339:                    HTChunk_puts(msg, " (");
2.1       frystyk   340:                    for (cnt=0; cnt<length; cnt++) {
                    341:                        char ch = *(pars+cnt);
                    342:                        if (ch < 0x20 || ch >= 0x7F)
2.3       frystyk   343:                            HTChunk_putc(msg, '#');
2.1       frystyk   344:                        else
2.3       frystyk   345:                            HTChunk_putc(msg, ch);
2.1       frystyk   346:                    }
2.3       frystyk   347:                    HTChunk_puts(msg, ") ");
2.1       frystyk   348:                }
                    349:            }
                    350: 
                    351:            if (showmask & HT_ERR_SHOW_LOCATION) {         /* Error Location */
2.3       frystyk   352:                HTChunk_puts(msg, "This occured in ");
                    353:                HTChunk_puts(msg, HTError_location(pres));
                    354:                HTChunk_putc(msg, '\n');
2.1       frystyk   355:            }
                    356: 
                    357:            /*
                    358:            ** Make sure that we don't get this error more than once even
                    359:            ** if we are keeping the error stack from one request to another
                    360:            */
                    361:            HTError_setIgnore(pres);
                    362:            
                    363:            /* If we only are show the most recent entry then break here */
                    364:            if (showmask & HT_ERR_SHOW_FIRST)
                    365:                break;
                    366:        }
                    367:     }
                    368:     if (msg) {
2.3       frystyk   369:        HTChunk_putc(msg, '\n');
2.8       eric      370:        HTTrace("WARNING: %s\n", HTChunk_data(msg));
2.3       frystyk   371:        HTChunk_delete(msg);
2.1       frystyk   372:     }
                    373:     return YES;
                    374: }
                    375: 
2.6       frystyk   376: /*     HTError_response
                    377: **     ----------------
                    378: **     Default function that creates an error message using HTAlert() to
                    379: **     put out the contents of the error_stack messages. Furthermore, the
                    380: **     error_info structure contains a name of a help file that might be put
                    381: **     up as a link. This file can then be multi-linguistic.
                    382: */
                    383: PUBLIC BOOL HTError_response (HTRequest * request, HTAlertOpcode op,
2.10      frystyk   384:                              int msgnum, const char * dfault, void * input,
2.6       frystyk   385:                              HTAlertPar * reply)
                    386: {
                    387:     HTList * cur = (HTList *) input;
                    388:     HTError * pres;
                    389:     HTErrorShow showmask = HTError_show();
                    390:     HTChunk * msg = NULL;
                    391:     int code;
2.8       eric      392:     if (WWWTRACE) HTTrace("HTError..... Generating HTTP response\n");
2.6       frystyk   393:     if (!request || !cur || !reply) return NO;
                    394:     while ((pres = (HTError *) HTList_nextObject(cur))) {
                    395:        int index = HTError_index(pres);
                    396:        if (HTError_doShow(pres)) {
                    397:            if (!msg) {
                    398:                msg = HTChunk_new(128);
                    399:                if ((code = HTErrors[index].code) > 0) {
                    400:                    char * reason = HTErrors[index].msg;
2.7       frystyk   401:                    char * buf;
                    402:                    if ((buf = (char  *) HT_MALLOC(20 + strlen(reason))) == NULL)
                    403:                        HT_OUTOFMEM("HTError_response");
2.6       frystyk   404:                    sprintf(buf,"%s %d %s%c%c",HTTP_VERSION,code,reason,CR,LF);
                    405:                    HTAlert_assignReplyMessage(reply, buf);
                    406:                }
                    407:            } else {
                    408:                HTChunk_puts(msg, "\nReason: ");
                    409:                HTChunk_puts(msg, HTErrors[index].msg);     /* Error message */
                    410:            }
                    411: 
                    412:            if (showmask & HT_ERR_SHOW_PARS) {           /* Error parameters */
                    413:                int length;
                    414:                int cnt;                
                    415:                char *pars = (char *) HTError_parameter(pres, &length);
                    416:                if (length && pars) {
                    417:                    HTChunk_puts(msg, " (");
                    418:                    for (cnt=0; cnt<length; cnt++) {
                    419:                        char ch = *(pars+cnt);
                    420:                        if (ch < 0x20 || ch >= 0x7F)
                    421:                            HTChunk_putc(msg, '#');
                    422:                        else
                    423:                            HTChunk_putc(msg, ch);
                    424:                    }
                    425:                    HTChunk_puts(msg, ") ");
                    426:                }
                    427:            }
                    428: 
                    429:            if (showmask & HT_ERR_SHOW_LOCATION) {         /* Error Location */
                    430:                HTChunk_puts(msg, "This occured in ");
                    431:                HTChunk_puts(msg, HTError_location(pres));
                    432:                HTChunk_putc(msg, '\n');
                    433:            }
                    434: 
                    435:            /*
                    436:            ** Make sure that we don't get this error more than once even
                    437:            ** if we are keeping the error stack from one request to another
                    438:            */
                    439:            HTError_setIgnore(pres);
                    440:            
                    441:            /* If we only are show the most recent entry then break here */
                    442:            if (showmask & HT_ERR_SHOW_FIRST)
                    443:                break;
                    444:        }
                    445:     }
                    446:     if (msg) {
                    447:        HTChunk_putc(msg, '\n');
                    448: #if 0
2.8       eric      449:        HTTrace("WARNING: %s\n", HTChunk_data(msg));
2.6       frystyk   450: #endif
                    451:        HTChunk_delete(msg);
                    452:     }
                    453:     return YES;
                    454: }

Webmaster