Annotation of libwww/Robot/src/HTRobot.c, revision 1.82

1.75      frystyk     1: /*
1.82    ! frystyk     2: **     @(#) $Id: HTRobot.c,v 1.81 1999/01/22 14:05:59 frystyk Exp $
1.75      frystyk     3: **     
                      4: **     W3C Webbot can be found at "http://www.w3.org/Robot/"
                      5: **     
                      6: **     Copyright  1995-1998 World Wide Web Consortium, (Massachusetts
                      7: **     Institute of Technology, Institut National de Recherche en
                      8: **     Informatique et en Automatique, Keio University). All Rights
                      9: **     Reserved. This program is distributed under the W3C's Software
                     10: **     Intellectual Property License. This program is distributed in the hope
                     11: **     that it will be useful, but WITHOUT ANY WARRANTY; without even the
                     12: **     implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
                     13: **     PURPOSE. See W3C License http://www.w3.org/Consortium/Legal/ for more
                     14: **     details.
1.1       frystyk    15: **
                     16: **  Authors:
                     17: **     HFN             Henrik Frystyk Nielsen, (frystyk@w3.org)
1.75      frystyk    18: **     BR              Bob Racko
                     19: **     JP              John Punin
1.1       frystyk    20: **
                     21: **  History:
                     22: **     Dec 04 95       First version
1.75      frystyk    23: **     Oct 1998        Split into separate files
1.1       frystyk    24: */
                     25: 
1.75      frystyk    26: #include "HTRobMan.h"
                     27: #include "HTQueue.h"
                     28: #include "HTAncMan.h"
1.51      frystyk    29: 
1.62      frystyk    30: #define SHOW_QUIET(mr)         ((mr) && !((mr)->flags & MR_QUIET))
                     31: #define SHOW_REAL_QUIET(mr)    ((mr) && !((mr)->flags & MR_REAL_QUIET))
1.1       frystyk    32: 
1.75      frystyk    33: PRIVATE HTErrorMessage HTErrors[HTERR_ELEMENTS] = {HTERR_ENGLISH_INITIALIZER};
1.58      frystyk    34: 
                     35: /*
                     36: **  Some sorting algorithms
                     37: */
1.63      frystyk    38: PRIVATE HTComparer HitSort, FormatSort, LastModifiedSort, TitleSort;
1.58      frystyk    39: 
1.80      frystyk    40: /*
                     41: **  Ths callbacks that we need from the libwww HTML parser
                     42: */
                     43: PRIVATE HText_new      RHText_new;
                     44: PRIVATE HText_delete   RHText_delete;
                     45: PRIVATE HText_foundLink        RHText_foundLink;
1.1       frystyk    46: 
                     47: /* ------------------------------------------------------------------------- */
                     48: 
1.2       frystyk    49: /*     Create a "HyperDoc" object
                     50: **     --------------------------
                     51: **     A HyperDoc object contains information about whether we have already
                     52: **     started checking the anchor and the depth in our search
                     53: */
1.75      frystyk    54: PUBLIC HyperDoc * HyperDoc_new (Robot * mr,HTParentAnchor * anchor, int depth)
1.2       frystyk    55: {
                     56:     HyperDoc * hd;
1.14      frystyk    57:     if ((hd = (HyperDoc *) HT_CALLOC(1, sizeof(HyperDoc))) == NULL)
                     58:        HT_OUTOFMEM("HyperDoc_new");
1.2       frystyk    59:     hd->depth = depth;
1.55      frystyk    60:     hd->hits = 1;
1.75      frystyk    61: 
                     62:     hd->code = -1;
                     63:     hd->index = ++mr->cindex;
                     64: 
1.2       frystyk    65:     /* Bind the HyperDoc object together with the Anchor Object */
                     66:     hd->anchor = anchor;
                     67:     HTAnchor_setDocument(anchor, (void *) hd);
                     68: 
                     69:     /* Add this HyperDoc object to our list */
                     70:     if (!mr->hyperdoc) mr->hyperdoc = HTList_new();
                     71:     HTList_addObject(mr->hyperdoc, (void *) hd);
                     72:     return hd;
                     73: }
                     74: 
                     75: /*     Delete a "HyperDoc" object
                     76: **     --------------------------
                     77: */
1.75      frystyk    78: PUBLIC BOOL HyperDoc_delete (HyperDoc * hd)
1.2       frystyk    79: {
                     80:     if (hd) {
1.11      frystyk    81:        HT_FREE (hd);
1.2       frystyk    82:        return YES;
                     83:     }
                     84:     return NO;
                     85: }
                     86: 
1.55      frystyk    87: /*
                     88: **  Sort the anchor array and log reference count
                     89: */
                     90: PRIVATE BOOL calculate_hits (Robot * mr, HTArray * array)
                     91: {
                     92:     if (mr && array) {
                     93:         HTLog * log = HTLog_open(mr->hitfile, YES, YES);
                     94:         if (log) {
                     95:             void ** data = NULL;
                     96:             HTParentAnchor * anchor = NULL;
                     97:             HTArray_sort(array, HitSort);
                     98:             anchor = (HTParentAnchor *) HTArray_firstObject(array, data);
                     99:            while (anchor) {
                    100:                 char * uri = HTAnchor_address((HTAnchor *) anchor);
                    101:                 HyperDoc * hd = (HyperDoc *) HTAnchor_document(anchor);
1.63      frystyk   102:                 if (uri && hd) HTLog_addText(log, "%8d %s\n", hd->hits, uri);
1.55      frystyk   103:                 HT_FREE(uri);
                    104:                 anchor = (HTParentAnchor *) HTArray_nextObject(array, data);
                    105:             }
                    106:        }
                    107:         HTLog_close(log);
                    108:         return YES;
                    109:     }
                    110:     return NO;
                    111: }
                    112: 
                    113: PRIVATE int HitSort (const void * a, const void * b)
                    114: {
                    115:     HyperDoc * aa = HTAnchor_document(*(HTParentAnchor **) a);
                    116:     HyperDoc * bb = HTAnchor_document(*(HTParentAnchor **) b);
                    117:     if (aa && bb) return (bb->hits - aa->hits);
                    118:     return bb - aa;
                    119: }
                    120: 
1.58      frystyk   121: /*
1.64      frystyk   122: **  Sort the anchor array and log link relations
                    123: */
                    124: PRIVATE BOOL calculate_linkRelations (Robot * mr, HTArray * array)
                    125: {
                    126:     if (mr && array) {
1.68      frystyk   127:         HTLog * log = mr->relfile ? HTLog_open(mr->relfile, YES, YES) : NULL;
                    128:        void ** data = NULL;
                    129:        HTParentAnchor * anchor = NULL;
                    130:        anchor = (HTParentAnchor *) HTArray_firstObject(array, data);
                    131:        while (anchor) {
                    132: 
                    133:            /*
                    134:            **  If we have a specific link relation to look for then do this.
                    135:            **  Otherwise look for all link relations.
                    136:            */
                    137:            if (mr->relation) {
                    138:                HTLink * link = HTAnchor_findLinkType((HTAnchor *) anchor, mr->relation);
                    139:                if (link) {
                    140:                    HTParentAnchor * dest = HTAnchor_parent(HTLink_destination(link));
                    141:                    char * src_uri = HTAnchor_address((HTAnchor *) anchor);
                    142:                    char * dest_uri = HTAnchor_address((HTAnchor *) dest);
                    143:                    if (src_uri && dest_uri) {
                    144: #ifdef HT_MYSQL
                    145:                        if (mr->sqllog) {
                    146:                            HTSQLLog_addLinkRelationship (mr->sqllog,
                    147:                                                          src_uri, dest_uri,
                    148:                                                          HTAtom_name(mr->relation),
                    149:                                                          NULL);
                    150:                        }
                    151: #endif
                    152:                        if (log) {
                    153:                            HTFormat format = HTAnchor_format(dest);
                    154:                            HTLog_addText(log, "%s %s %s --> %s\n",
                    155:                                          HTAtom_name(mr->relation),
                    156:                                          format != WWW_UNKNOWN ?
                    157:                                          HTAtom_name(format) : "<unknown>",
                    158:                                          src_uri, dest_uri);
                    159:                        }
                    160: 
                    161:                        /* Cleanup */
                    162:                        HT_FREE(src_uri);
                    163:                        HT_FREE(dest_uri);
                    164:                    }
                    165:                }
                    166:            } else {
                    167:                HTLink * link = HTAnchor_mainLink((HTAnchor *) anchor);
                    168:                HTList * sublinks = HTAnchor_subLinks((HTAnchor *) anchor);
                    169:                char * src_uri = HTAnchor_address((HTAnchor *) anchor);
                    170:                HTLinkType linktype;
                    171: 
                    172:                /* First look in the main link */
                    173:                if (link && (linktype = HTLink_type(link))) {               
                    174:                    HTParentAnchor * dest = HTAnchor_parent(HTLink_destination(link));
                    175:                    char * dest_uri = HTAnchor_address((HTAnchor *) dest);
                    176:                    if (src_uri && dest_uri) {
                    177: #ifdef HT_MYSQL
                    178:                        if (mr->sqllog) {
                    179:                            HTSQLLog_addLinkRelationship (mr->sqllog,
                    180:                                                          src_uri, dest_uri,
                    181:                                                          HTAtom_name(linktype),
                    182:                                                          NULL);
                    183:                        }
                    184: #endif
                    185:                        if (log) {
                    186:                            HTFormat format = HTAnchor_format(dest);
                    187:                            HTLog_addText(log, "%s %s %s --> %s\n",
                    188:                                          HTAtom_name(linktype),
                    189:                                          format != WWW_UNKNOWN ?
                    190:                                          HTAtom_name(format) : "<unknown>",
                    191:                                          src_uri, dest_uri);
                    192:                        }
                    193:                    }
                    194:                    HT_FREE(dest_uri);
                    195:                }
                    196: 
                    197:                /* and then in any sublinks */
                    198:                if (sublinks) {
                    199:                    HTLink * pres;
                    200:                    while ((pres = (HTLink *) HTList_nextObject(sublinks))) {
                    201:                        if ((linktype = HTLink_type(pres))) {
                    202:                            HTParentAnchor * dest = HTAnchor_parent(HTLink_destination(pres));
1.64      frystyk   203:                            char * dest_uri = HTAnchor_address((HTAnchor *) dest);
1.68      frystyk   204:                            if (src_uri && dest_uri) {
                    205: #ifdef HT_MYSQL
                    206:                                if (mr->sqllog) {
                    207:                                    HTSQLLog_addLinkRelationship (mr->sqllog,
                    208:                                                                  src_uri, dest_uri,
                    209:                                                                  HTAtom_name(linktype),
                    210:                                                                  NULL);
                    211:                                }
                    212: #endif
                    213:                                if (log) {
                    214:                                    HTFormat format = HTAnchor_format(dest);
                    215:                                    HTLog_addText(log, "%s %s %s --> %s\n",
                    216:                                                  HTAtom_name(linktype),
                    217:                                                  format != WWW_UNKNOWN ?
                    218:                                                  HTAtom_name(format) : "<unknown>",
                    219:                                                  src_uri, dest_uri);
                    220:                                }
1.64      frystyk   221:                                HT_FREE(dest_uri);
                    222:                            }
                    223:                        }
                    224:                    }
                    225:                }
1.68      frystyk   226: 
                    227:                /* Cleanup */
                    228:                HT_FREE(src_uri);
                    229:            }
                    230:            anchor = (HTParentAnchor *) HTArray_nextObject(array, data);
1.64      frystyk   231:        }
1.68      frystyk   232:         if (log) HTLog_close(log);
1.64      frystyk   233:         return YES;
                    234:     }
                    235:     return NO;
                    236: }
                    237: 
                    238: /*
1.63      frystyk   239: **  Sort the anchor array and log last modified date
                    240: */
                    241: PRIVATE BOOL calculate_lm (Robot * mr, HTArray * array)
                    242: {
                    243:     if (mr && array) {
                    244:         HTLog * log = HTLog_open(mr->lmfile, YES, YES);
                    245:         if (log) {
                    246:             void ** data = NULL;
                    247:             HTParentAnchor * anchor = NULL;
                    248:             HTArray_sort(array, LastModifiedSort);
                    249:             anchor = (HTParentAnchor *) HTArray_firstObject(array, data);
                    250:            while (anchor) {
                    251:                 char * uri = HTAnchor_address((HTAnchor *) anchor);
                    252:                 time_t lm = HTAnchor_lastModified(anchor);
                    253:                 if (uri && lm > 0)
                    254:                    HTLog_addText(log, "%s %s\n", HTDateTimeStr(&lm, NO), uri);
                    255:                 HT_FREE(uri);
                    256:                 anchor = (HTParentAnchor *) HTArray_nextObject(array, data);
                    257:             }
                    258:        }
                    259:         HTLog_close(log);
                    260:         return YES;
                    261:     }
                    262:     return NO;
                    263: }
                    264: 
                    265: PRIVATE int LastModifiedSort (const void * a, const void * b)
                    266: {
                    267:     time_t aa = HTAnchor_lastModified(*(HTParentAnchor **) a);
                    268:     time_t bb = HTAnchor_lastModified(*(HTParentAnchor **) b);
                    269:     return bb - aa;
                    270: }
                    271: 
                    272: /*
                    273: **  Sort the anchor array and log the document title
                    274: */
                    275: PRIVATE BOOL calculate_title (Robot * mr, HTArray * array)
                    276: {
                    277:     if (mr && array) {
                    278:         HTLog * log = HTLog_open(mr->titlefile, YES, YES);
                    279:         if (log) {
                    280:             void ** data = NULL;
                    281:             HTParentAnchor * anchor = NULL;
                    282:             HTArray_sort(array, TitleSort);
                    283:             anchor = (HTParentAnchor *) HTArray_firstObject(array, data);
                    284:            while (anchor) {
                    285:                 char * uri = HTAnchor_address((HTAnchor *) anchor);
                    286:                 const char * title = HTAnchor_title(anchor);
                    287:                HTCharset charset = HTAnchor_charset(anchor);
                    288:                 if (uri) HTLog_addText(log, "%s `%s\' %s\n",
                    289:                                       charset ? HTAtom_name(charset) : "<none>",
                    290:                                       title ? title : "<none>",
                    291:                                       uri);
                    292:                 HT_FREE(uri);
                    293:                 anchor = (HTParentAnchor *) HTArray_nextObject(array, data);
                    294:             }
                    295:        }
                    296:         HTLog_close(log);
                    297:         return YES;
                    298:     }
                    299:     return NO;
                    300: }
                    301: 
                    302: PRIVATE int TitleSort (const void * a, const void * b)
                    303: {
                    304:     const char * aa = HTAnchor_title(*(HTParentAnchor **) a);
                    305:     const char * bb = HTAnchor_title(*(HTParentAnchor **) b);
                    306:     return strcasecomp(bb?bb:"", aa?aa:"");
                    307: }
                    308: 
                    309: /*
1.58      frystyk   310: **  Calculate distributions for media types. The same mechanism
                    311: **  can be used for other characteristics with relatively
                    312: **  few outcomes.
                    313: */
                    314: PRIVATE HTList * mediatype_distribution (HTArray * array)
                    315: {
                    316:     if (array) {
                    317:        HTList * mt = HTList_new();
                    318:        MetaDist * pres = NULL;
                    319:        void ** data = NULL;
                    320:        HTParentAnchor * anchor = NULL;
                    321:        anchor = (HTParentAnchor *) HTArray_firstObject(array, data);
                    322:        while (anchor) {
                    323:            HTFormat format = HTAnchor_format(anchor);
                    324:            if (format && format != WWW_UNKNOWN) {
                    325:                HTList * cur = mt;
                    326: 
                    327:                /* If found then increase counter */
                    328:                while ((pres = (MetaDist *) HTList_nextObject(cur))) {
                    329:                    if (pres->name == format) {
                    330:                        pres->hits++;
                    331:                        break;
                    332:                    }
                    333:                }
                    334: 
                    335:                /* If not found then add new format to list */
                    336:                if (!pres) {
                    337:                     if ((pres = (MetaDist *) HT_CALLOC(1, sizeof(MetaDist))) == NULL)
                    338:                         HT_OUTOFMEM("mediatype_distribution");
                    339:                    pres->name = format;
                    340:                    pres->hits = 1;
                    341:                    HTList_addObject(mt, pres);
                    342:                    HTList_insertionSort(mt, FormatSort);
                    343:                }
                    344:            }
                    345: 
                    346:            /* Find next anchor in array */
                    347:            anchor = (HTParentAnchor *) HTArray_nextObject(array, data);
                    348:        }
                    349:        return mt;
                    350:     }
                    351:     return NULL;
                    352: }
                    353: 
1.60      frystyk   354: /*
                    355: **  Calculate distributions for charsets. The same mechanism
                    356: **  can be used for other characteristics with relatively
                    357: **  few outcomes.
                    358: */
                    359: PRIVATE HTList * charset_distribution (HTArray * array)
                    360: {
                    361:     if (array) {
                    362:        HTList * cs = HTList_new();
                    363:        MetaDist * pres = NULL;
                    364:        void ** data = NULL;
                    365:        HTParentAnchor * anchor = NULL;
                    366:        anchor = (HTParentAnchor *) HTArray_firstObject(array, data);
                    367:        while (anchor) {
                    368:            HTCharset charset = HTAnchor_charset(anchor);
                    369:            if (charset) {
                    370:                HTList * cur = cs;
                    371: 
                    372:                /* If found then increase counter */
                    373:                while ((pres = (MetaDist *) HTList_nextObject(cur))) {
                    374:                    if (pres->name == charset) {
                    375:                        pres->hits++;
                    376:                        break;
                    377:                    }
                    378:                }
                    379: 
                    380:                /* If not found then add new format to list */
                    381:                if (!pres) {
                    382:                     if ((pres = (MetaDist *) HT_CALLOC(1, sizeof(MetaDist))) == NULL)
                    383:                         HT_OUTOFMEM("charset_distribution");
                    384:                    pres->name = charset;
                    385:                    pres->hits = 1;
                    386:                    HTList_addObject(cs, pres);
                    387:                    HTList_insertionSort(cs, FormatSort);
                    388:                }
                    389:            }
                    390: 
                    391:            /* Find next anchor in array */
                    392:            anchor = (HTParentAnchor *) HTArray_nextObject(array, data);
                    393:        }
                    394:        return cs;
                    395:     }
                    396:     return NULL;
                    397: }
                    398: 
1.58      frystyk   399: PRIVATE int FormatSort (const void * a, const void * b)
                    400: {
                    401:     MetaDist * aa = (MetaDist *) a;
                    402:     MetaDist * bb = (MetaDist *) b;
                    403:     return strcmp(HTAtom_name(bb->name), HTAtom_name(aa->name));
                    404: }
                    405: 
                    406: PRIVATE BOOL log_meta_distribution (const char * logfile, HTList * distribution)
                    407: {
                    408:     if (logfile && distribution) {
                    409:         HTLog * log = HTLog_open(logfile, YES, YES);
                    410:        if (log) {
                    411:            HTList * cur = distribution;
                    412:            MetaDist * pres;
                    413:            while ((pres = (MetaDist *) HTList_nextObject(cur))) {
                    414:                if (pres->name) {
1.60      frystyk   415:                    HTLog_addText(log, "%8d %s\n", pres->hits, HTAtom_name(pres->name));
1.58      frystyk   416:                }
                    417:            }
                    418:            HTLog_close(log);
                    419:        }
                    420:     }
                    421:     return NO;
                    422: }
                    423: 
                    424: PRIVATE BOOL delete_meta_distribution (HTList * distribution)
                    425: {
                    426:     if (distribution) {
                    427:        HTList * cur = distribution;
                    428:        MetaDist * pres;
                    429:        while ((pres = (MetaDist *) HTList_nextObject(cur)))
                    430:            HT_FREE(pres);
                    431:        HTList_delete(distribution);    
                    432:        return YES;     
                    433:     }
                    434:     return NO;
                    435: }
                    436: 
                    437: 
1.55      frystyk   438: /*     Statistics
                    439: **     ----------
                    440: **     Calculates a bunch of statistics for the anchors traversed
                    441: */
                    442: PRIVATE BOOL calculate_statistics (Robot * mr)
                    443: {
1.59      frystyk   444:     long total_docs = mr->get_docs + mr->head_docs + mr->other_docs;
1.55      frystyk   445:     if (!mr) return NO;
                    446: 
                    447:     /* Calculate efficiency */
1.59      frystyk   448:     if (mr->time > 0) {
1.56      frystyk   449:        ms_t t = HTGetTimeInMillis() - mr->time;
                    450:        if (t > 0) {
1.60      frystyk   451:            double loadfactor = (mr->get_bytes / (t * 0.001));
                    452:            double reqprsec = (total_docs / (t * 0.001));
1.56      frystyk   453:            double secs = t / 1000.0;
1.55      frystyk   454:             char bytes[50];
1.62      frystyk   455:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   456:                HTPrint("\nAccessed %ld documents in %.2f seconds (%.2f requests pr sec)\n",
1.62      frystyk   457:                        total_docs, secs, reqprsec);
1.59      frystyk   458: 
                    459:             HTNumToStr(mr->get_bytes, bytes, 50);
1.62      frystyk   460:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   461:                HTPrint("\tDid a GET on %ld document(s) and downloaded %s bytes of document bodies (%2.1f bytes/sec)\n",
1.62      frystyk   462:                        mr->get_docs, bytes, loadfactor);
1.59      frystyk   463: 
                    464:             HTNumToStr(mr->head_bytes, bytes, 50);
1.62      frystyk   465:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   466:                HTPrint("\tDid a HEAD on %ld document(s) with a total of %s bytes\n",
1.62      frystyk   467:                        mr->head_docs, bytes);
1.55      frystyk   468:        }
                    469:     }
                    470: 
                    471:     /* Create an array of existing anchors */
1.59      frystyk   472:     if (total_docs > 1) {
                    473:        HTArray * array = HTAnchor_getArray(total_docs);
1.55      frystyk   474:         if (array) {
                    475: 
1.63      frystyk   476:            /* Distributions */
                    477:            if (mr->flags & MR_DISTRIBUTIONS) {
1.82    ! frystyk   478:                if (SHOW_REAL_QUIET(mr)) HTPrint("\nDistributions:\n");
1.63      frystyk   479:            }
                    480: 
1.55      frystyk   481:             /* Sort after hit counts */
1.63      frystyk   482:             if (mr->hitfile) {
                    483:                if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   484:                    HTPrint("\tLogged hit count distribution in file `%s\'\n",
1.63      frystyk   485:                            mr->hitfile);
                    486:                calculate_hits(mr, array);
                    487:            }
                    488: 
1.64      frystyk   489:             /* Sort after link relations */
1.68      frystyk   490: #ifdef HT_MYSQL
                    491:             if (mr->relfile || mr->sqllog) {
1.69      frystyk   492: #else
                    493:             if (mr->relfile) {
                    494: #endif
1.68      frystyk   495:                if (mr->relfile && SHOW_REAL_QUIET(mr))
1.82    ! frystyk   496:                    HTPrint("\tLogged link relationship distribution in file `%s\'\n",
1.64      frystyk   497:                            mr->relfile);
                    498:                calculate_linkRelations(mr, array);
                    499:            }
                    500: 
1.63      frystyk   501:             /* Sort after modified date */
                    502:             if (mr->lmfile) {
                    503:                if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   504:                    HTPrint("\tLogged last modified distribution in file `%s\'\n",
1.63      frystyk   505:                            mr->lmfile);
                    506:                calculate_lm(mr, array);
                    507:            }
                    508: 
                    509:             /* Sort after title */
                    510:             if (mr->titlefile) {
                    511:                if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   512:                    HTPrint("\tLogged title distribution in file `%s\'\n",
1.63      frystyk   513:                            mr->titlefile);
                    514:                calculate_title(mr, array);
                    515:            }
1.55      frystyk   516: 
1.58      frystyk   517:             /* Find mediatype distribution */
                    518:            if (mr->mtfile) {
                    519:                HTList * mtdist = mediatype_distribution(array);
                    520:                if (mtdist) {
1.63      frystyk   521:                    if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   522:                        HTPrint("\tLogged media type distribution in file `%s\'\n",
1.63      frystyk   523:                                mr->mtfile);
1.58      frystyk   524:                    log_meta_distribution(mr->mtfile, mtdist);
                    525:                    delete_meta_distribution(mtdist);
                    526:                }
                    527:            }
1.55      frystyk   528: 
1.60      frystyk   529:             /* Find charset distribution */
                    530:            if (mr->charsetfile) {
                    531:                HTList * charsetdist = charset_distribution(array);
                    532:                if (charsetdist) {
1.63      frystyk   533:                    if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   534:                        HTPrint("\tLogged charset distribution in file `%s\'\n",
1.63      frystyk   535:                                mr->charsetfile);
1.60      frystyk   536:                    log_meta_distribution(mr->charsetfile, charsetdist);
                    537:                    delete_meta_distribution(charsetdist);
                    538:                }
                    539:            }
                    540: 
1.55      frystyk   541:             /* Add as may other stats here as you like */
1.60      frystyk   542:            /* ... */
1.58      frystyk   543:            
                    544:            /* Delete the array */
1.55      frystyk   545:             HTArray_delete(array);
                    546:         }
                    547:     }
                    548:     return YES;
                    549: }
                    550: 
1.75      frystyk   551: PRIVATE HTParentAnchor *
                    552: get_last_parent(HTParentAnchor *anchor)
                    553: {
                    554:   HTAnchor *anc;
                    555:   HTList *sources = anchor->sources;
                    556: 
                    557:   while((anc = (HTAnchor *) HTList_nextObject(sources)) != NULL)
                    558:     {
                    559:       HTParentAnchor *panchor = HTAnchor_parent(anc);
                    560:       return panchor;
                    561:     }
                    562:   return NULL;
                    563: }
                    564: 
                    565: PRIVATE void
                    566: set_error_state_hyperdoc(HyperDoc * hd, HTRequest *request)
                    567: {
                    568:   HTList * cur = HTRequest_error(request);
                    569:   HTError *pres;
                    570: 
                    571:   while((pres = (HTError *) HTList_nextObject(cur)) != NULL)
                    572:     {
                    573:       int code =HTErrors[HTError_index(pres)].code;
                    574: 
                    575:       hd->code = code;
                    576:     }
                    577: }
                    578: 
                    579: 
                    580: PRIVATE int
                    581: test_for_blank_spaces(char *uri)
                    582: {
                    583:   char *ptr = uri;
                    584:   for(;*ptr!='\0';ptr++)
                    585:     if(*ptr == ' ')
                    586:       return 1;
                    587:   return 0;
                    588: }
                    589: 
                    590: 
1.1       frystyk   591: /*     Create a Command Line Object
                    592: **     ----------------------------
                    593: */
1.75      frystyk   594: PUBLIC Robot * Robot_new (void)
1.1       frystyk   595: {
                    596:     Robot * me;
1.41      frystyk   597:     if ((me = (Robot *) HT_CALLOC(1, sizeof(Robot))) == NULL)
1.14      frystyk   598:        HT_OUTOFMEM("Robot_new");
1.2       frystyk   599:     me->hyperdoc = HTList_new();
1.4       frystyk   600:     me->htext = HTList_new();
1.74      frystyk   601:     me->timer = DEFAULT_TIMEOUT*MILLIES;
1.75      frystyk   602:     me->waits = 0;
1.25      frystyk   603:     me->cwd = HTGetCurrentDirectoryURL();
1.1       frystyk   604:     me->output = OUTPUT;
1.35      eric      605:     me->cnt = 0;
1.75      frystyk   606:     me->ndoc = -1;
1.34      eric      607:     me->fingers = HTList_new();
1.75      frystyk   608:  
                    609:    /* This is new */
                    610:     me->queue = HTQueue_new();
                    611:     me->cq = 0;
                    612:     me->furl = NULL;
                    613: 
1.1       frystyk   614:     return me;
                    615: }
                    616: 
                    617: /*     Delete a Command Line Object
                    618: **     ----------------------------
                    619: */
1.62      frystyk   620: PRIVATE BOOL Robot_delete (Robot * mr)
1.1       frystyk   621: {
1.62      frystyk   622:     if (mr) {
                    623:        HTList_delete(mr->fingers);
1.55      frystyk   624: 
                    625:                /* Calculate statistics */
1.62      frystyk   626:        calculate_statistics(mr);
1.55      frystyk   627: 
1.62      frystyk   628:         if (mr->hyperdoc) {
                    629:            HTList * cur = mr->hyperdoc;
1.2       frystyk   630:            HyperDoc * pres;
                    631:            while ((pres = (HyperDoc *) HTList_nextObject(cur)))
                    632:                HyperDoc_delete(pres);
1.62      frystyk   633:            HTList_delete(mr->hyperdoc);
1.2       frystyk   634:        }
1.62      frystyk   635:        if (mr->htext) {
                    636:            HTList * cur = mr->htext;
1.4       frystyk   637:            HText * pres;
                    638:            while ((pres = (HText *) HTList_nextObject(cur)))
1.80      frystyk   639:                RHText_delete(pres);
1.62      frystyk   640:            HTList_delete(mr->htext);
1.4       frystyk   641:        }
1.62      frystyk   642: 
                    643:        /* Close all the log files */
1.63      frystyk   644:        if (mr->flags & MR_LOGGING) {
1.82    ! frystyk   645:            if (SHOW_REAL_QUIET(mr)) HTPrint("\nRaw Log files:\n");
1.63      frystyk   646:        }
                    647: 
1.62      frystyk   648:        if (mr->log) {
                    649:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   650:                HTPrint("\tLogged %5d entries in general log file `%s\'\n",
1.62      frystyk   651:                        HTLog_accessCount(mr->log), mr->logfile);
                    652:            HTLog_close(mr->log);
                    653:        }
                    654:        if (mr->ref) {
                    655:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   656:                HTPrint("\tLogged %5d entries in referer log file `%s\'\n",
1.62      frystyk   657:                        HTLog_accessCount(mr->ref), mr->reffile);
                    658:            HTLog_close(mr->ref);
                    659:        }
                    660:        if (mr->reject) {
                    661:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   662:                HTPrint("\tLogged %5d entries in rejected log file `%s\'\n",
1.62      frystyk   663:                        HTLog_accessCount(mr->reject), mr->rejectfile);
                    664:            HTLog_close(mr->reject);
                    665:        }
                    666:        if (mr->notfound) {
                    667:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   668:                HTPrint("\tLogged %5d entries in not found log file `%s\'\n",
1.62      frystyk   669:                        HTLog_accessCount(mr->notfound), mr->notfoundfile);
                    670:            HTLog_close(mr->notfound);
                    671:        }
                    672:        if (mr->conneg) {
                    673:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   674:                HTPrint("\tLogged %5d entries in content negotiation log file `%s\'\n",
1.62      frystyk   675:                        HTLog_accessCount(mr->conneg), mr->connegfile);
                    676:            HTLog_close(mr->conneg);
                    677:        }
                    678:        if (mr->noalttag) {
                    679:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   680:                HTPrint("\tLogged %5d entries in missing alt tag log file `%s\'\n",
1.62      frystyk   681:                        HTLog_accessCount(mr->noalttag), mr->noalttagfile);
                    682:            HTLog_close(mr->noalttag);
                    683:        }
                    684: 
                    685:        if (mr->output && mr->output != STDOUT) fclose(mr->output);
                    686: 
                    687:        if (mr->flags & MR_TIME) {
1.12      frystyk   688:            time_t local = time(NULL);
1.62      frystyk   689:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   690:                HTPrint("\nRobot terminated %s\n", HTDateTimeStr(&local, YES));
1.12      frystyk   691:        }
1.55      frystyk   692: 
1.75      frystyk   693:        /* This is new */
                    694:        if(mr->cdepth)
                    695:          HT_FREE(mr->cdepth);
                    696:        if(mr->furl) HT_FREE(mr->furl);
                    697: 
1.58      frystyk   698: #ifdef HT_POSIX_REGEX
1.62      frystyk   699:        if (mr->include) {
                    700:            regfree(mr->include);
                    701:            HT_FREE(mr->include);
                    702:        }
                    703:        if (mr->exclude) {
                    704:            regfree(mr->exclude);
                    705:            HT_FREE(mr->exclude);
                    706:        }
1.75      frystyk   707:        if (mr->exc_robot) {
                    708:            regfree(mr->exc_robot);
                    709:            HT_FREE(mr->exc_robot);
                    710:        }
1.62      frystyk   711:        if (mr->check) {
                    712:            regfree(mr->check);
                    713:            HT_FREE(mr->check);
1.58      frystyk   714:        }
                    715: #endif
                    716: 
1.68      frystyk   717: #ifdef HT_MYSQL
                    718:        if (mr->sqllog) {
                    719:            HTSQLLog_close(mr->sqllog);
                    720:            mr->sqllog = NULL;
                    721:        }
                    722: #endif
                    723: 
1.81      frystyk   724:        if (mr->queue) HTQueue_delete(mr->queue);
1.62      frystyk   725:        HT_FREE(mr->cwd);
                    726:        HT_FREE(mr->prefix);
                    727:        HT_FREE(mr->img_prefix);
                    728:        HT_FREE(mr);
1.1       frystyk   729:        return YES;
                    730:     }
                    731:     return NO;
                    732: }
                    733: 
1.2       frystyk   734: /*
1.34      eric      735: **  This function creates a new finger object and initializes it with a new request
1.2       frystyk   736: */
1.75      frystyk   737: PUBLIC Finger * Finger_new (Robot * robot, HTParentAnchor * dest, HTMethod method)
1.2       frystyk   738: {
1.34      eric      739:     Finger * me;
                    740:     HTRequest * request = HTRequest_new();
                    741:     if ((me = (Finger *) HT_CALLOC(1, sizeof(Finger))) == NULL)
                    742:        HT_OUTOFMEM("Finger_new");
                    743:     me->robot = robot;
                    744:     me->request = request;
                    745:     me->dest = dest;
                    746:     HTList_addObject(robot->fingers, (void *)me);
                    747: 
1.48      frystyk   748:     /* Set the context for this request */
1.34      eric      749:     HTRequest_setContext (request, me);
1.48      frystyk   750: 
                    751:     /* Check the various flags to customize the request */
                    752:     if (robot->flags & MR_PREEMPTIVE)
                    753:        HTRequest_setPreemptive(request, YES);
                    754:     if (robot->flags & MR_VALIDATE)
                    755:        HTRequest_setReloadMode(request, HT_CACHE_VALIDATE);
                    756:     if (robot->flags & MR_END_VALIDATE)
                    757:        HTRequest_setReloadMode(request, HT_CACHE_END_VALIDATE);
                    758: 
                    759:     /* We wanna make sure that we are sending a Host header (default) */
1.34      eric      760:     HTRequest_addRqHd(request, HT_C_HOST);
1.48      frystyk   761: 
                    762:     /* Set the method for this request */
1.34      eric      763:     HTRequest_setMethod(request, method);
                    764:     robot->cnt++;
                    765:     return me;
1.2       frystyk   766: }
                    767: 
1.34      eric      768: PRIVATE int Finger_delete (Finger * me)
1.2       frystyk   769: {
1.34      eric      770:     HTList_removeObject(me->robot->fingers, (void *)me);
                    771:     me->robot->cnt--;
1.37      frystyk   772: 
                    773:     /*
                    774:     **  If we are down at one request then flush the output buffer
                    775:     */
                    776:     if (me->request) {
                    777:        if (me->robot->cnt == 1) HTRequest_forceFlush(me->request);
1.34      eric      778:        HTRequest_delete(me->request);
1.37      frystyk   779:     }
                    780: 
                    781:     /*
                    782:     **  Delete the request and free myself
                    783:     */
1.34      eric      784:     HT_FREE(me);
                    785:     return YES;
1.2       frystyk   786: }
                    787: 
                    788: /*
                    789: **  Cleanup and make sure we close all connections including the persistent
                    790: **  ones
                    791: */
1.75      frystyk   792: PUBLIC void Cleanup (Robot * me, int status)
1.1       frystyk   793: {
1.81      frystyk   794:     HTProfile_delete();
1.1       frystyk   795:     Robot_delete(me);
1.50      frystyk   796: #ifdef HT_MEMLOG
1.39      eric      797:     HTMemLog_close();
1.47      frystyk   798: #endif
                    799: 
1.1       frystyk   800: #ifdef VMS
                    801:     exit(status ? status : 1);
                    802: #else
                    803:     exit(status ? status : 0);
                    804: #endif
                    805: }
                    806: 
1.58      frystyk   807: #ifdef HT_POSIX_REGEX
                    808: PRIVATE char * get_regerror (int errcode, regex_t * compiled)
                    809: {
                    810:     size_t length = regerror (errcode, compiled, NULL, 0);
                    811:     char * str = NULL;
                    812:     if ((str = (char *) HT_MALLOC(length+1)) == NULL)
                    813:        HT_OUTOFMEM("get_regerror");
                    814:     (void) regerror (errcode, compiled, str, length);
                    815:     return str;
                    816: }
                    817: 
1.75      frystyk   818: PUBLIC regex_t * get_regtype (Robot * mr, const char * regex_str, int cflags)
1.58      frystyk   819: {
                    820:     regex_t * regex = NULL;
                    821:     if (regex_str && *regex_str) {
                    822:        int status;
                    823:        if ((regex = (regex_t *) HT_CALLOC(1, sizeof(regex_t))) == NULL)
                    824:            HT_OUTOFMEM("get_regtype");
1.60      frystyk   825:        if ((status = regcomp(regex, regex_str, cflags))) {
1.58      frystyk   826:            char * err_msg = get_regerror(status, regex);
1.62      frystyk   827:            if (SHOW_REAL_QUIET(mr))
1.82    ! frystyk   828:                HTPrint("Regular expression error: %s\n", err_msg);
1.58      frystyk   829:            HT_FREE(err_msg);
                    830:            Cleanup(mr, -1);
                    831:        }
                    832:     }
                    833:     return regex;
                    834: }
                    835: #endif
                    836: 
1.75      frystyk   837: PUBLIC void VersionInfo (void)
1.1       frystyk   838: {
1.82    ! frystyk   839:     HTPrint("\nW3C OpenSource Software");
        !           840:     HTPrint("\n-----------------------\n\n");
        !           841:     HTPrint("\tWebbot version %s\n", APP_VERSION);
        !           842:     HTPrint("\tusing the W3C libwww library version %s.\n\n",HTLib_version());
        !           843:     HTPrint("\tSee \"%s\" for help\n", COMMAND_LINE);
        !           844:     HTPrint("\tSee \"http://www.w3.org/Robot/User/\" for user information\n");
        !           845:     HTPrint("\tSee \"http://www.w3.org/Robot/\" for general information\n\n");
        !           846:     HTPrint("\tPlease send feedback to the <www-lib@w3.org> mailing list,\n");
        !           847:     HTPrint("\tsee \"http://www.w3.org/Library/#Forums\" for details\n\n");
1.1       frystyk   848: }
                    849: 
                    850: /*     terminate_handler
                    851: **     -----------------
1.2       frystyk   852: **     This function is registered to handle the result of the request.
                    853: **     If no more requests are pending then terminate program
1.1       frystyk   854: */
1.75      frystyk   855: PUBLIC int terminate_handler (HTRequest * request, HTResponse * response,
1.32      frystyk   856:                               void * param, int status) 
1.1       frystyk   857: {
1.34      eric      858:     Finger * finger = (Finger *) HTRequest_context(request);
1.46      eric      859:     Robot * mr = finger->robot;
1.82    ! frystyk   860:     if (SHOW_QUIET(mr)) HTPrint("Robot....... done with %s\n", HTAnchor_physical(finger->dest));
1.55      frystyk   861: 
1.68      frystyk   862: #ifdef HT_MYSQL
                    863:     if (mr->sqllog) HTSQLLog_addEntry(mr->sqllog, request, status);
                    864: #endif
                    865: 
1.58      frystyk   866:     /* Check if negotiated resource and whether we should log that*/
                    867:     if (mr->conneg) {
                    868:        HTAssocList * cur = HTResponse_variant(response);
                    869:        if (cur) {
                    870:            BOOL first = YES;
                    871:            HTChunk * buffer = HTChunk_new(128);
                    872:            char * uri = HTAnchor_address((HTAnchor *) finger->dest);
                    873:            HTAssoc * pres;
1.60      frystyk   874:            HTChunk_puts(buffer, uri);
1.58      frystyk   875:            while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
                    876:                char * value = HTAssoc_value(pres);
                    877:                if (first) {
1.60      frystyk   878:                    HTChunk_puts(buffer, "\t(");
1.58      frystyk   879:                    first = NO;
                    880:                } else
                    881:                    HTChunk_puts(buffer, ", ");
                    882: 
                    883:                /* Output the name */
                    884:                HTChunk_puts(buffer, HTAssoc_name(pres));
                    885: 
                    886:                /* Only output the value if not empty string */
1.60      frystyk   887:                if (value && *value) {
1.58      frystyk   888:                    HTChunk_puts(buffer, "=");
                    889:                    HTChunk_puts(buffer, value);
                    890:                }
                    891:            }
1.60      frystyk   892:            if (!first) HTChunk_puts(buffer, ")");
                    893:            HTLog_addLine(mr->conneg, HTChunk_data(buffer));
1.58      frystyk   894:            HTChunk_delete(buffer);
                    895:            HT_FREE(uri);
                    896:        }
                    897:     }
                    898: 
1.55      frystyk   899:     /* Count the amount of body data that we have read */
1.59      frystyk   900:     if (HTRequest_method(request) == METHOD_GET) {
                    901:        int length = HTAnchor_length(HTRequest_anchor(request));
                    902:        if (length > 0) mr->get_bytes += length;
                    903:        mr->get_docs++;
                    904:     } else if (HTRequest_method(request) == METHOD_HEAD) {
1.56      frystyk   905:        int length = HTAnchor_length(HTRequest_anchor(request));
1.59      frystyk   906:        if (length > 0) mr->head_bytes += length;
                    907:        mr->head_docs++;
                    908:     } else {
                    909:        mr->other_docs++;
1.55      frystyk   910:     }
                    911: 
1.78      frystyk   912:     if (!(mr->flags & MR_BFS)) {
                    913: 
                    914:        /* Delete this thread */
                    915:        Finger_delete(finger);
                    916: 
                    917:        /* Should we stop? */
                    918:        if (mr->cnt <= 0) {
1.82    ! frystyk   919:            if (SHOW_QUIET(mr)) HTPrint("             Everything is finished...\n");
1.78      frystyk   920:            Cleanup(mr, 0);                     /* No way back from here */
                    921:        }
                    922:     }
                    923: 
1.82    ! frystyk   924:     if (SHOW_QUIET(mr)) HTPrint("             %d outstanding request%s\n", mr->cnt, mr->cnt == 1 ? "" : "s");
1.75      frystyk   925:     return HT_OK;
                    926: 
                    927: }
                    928: PUBLIC int my_terminate_handler (HTRequest * request, HTResponse * response,
                    929:                               void * param, int status) 
                    930: {
                    931:     Finger * finger = (Finger *) HTRequest_context(request);
                    932:     Robot * mr = finger->robot;
                    933:     HTParentAnchor * dest = finger->dest;
                    934:     HyperDoc * hd = HTAnchor_document(dest);
                    935:     int depth = (hd ? hd->depth : -1);
                    936: 
                    937:     if (hd) set_error_state_hyperdoc(hd,request);
                    938:       
                    939:     if(hd && (HTRequest_method(request)== METHOD_HEAD) && 
                    940:        (depth < mr->depth))
                    941:       {
                    942:        hd->method = METHOD_GET;
                    943:        HTQueue_append(mr->queue, (void *)hd); (mr->cq)++;
                    944:       }
1.58      frystyk   945: 
1.34      eric      946:     Finger_delete(finger);
1.55      frystyk   947: 
1.75      frystyk   948:     if(!(mr->flags & MR_PREEMPTIVE))
                    949:       Serving_queue(mr);
                    950: 
                    951:     return HT_OK;
                    952: }
                    953: 
                    954: 
                    955: PUBLIC void Serving_queue(Robot *mr)
                    956: {
                    957:   BOOL abort = NO;
                    958:   Finger *nfinger;
                    959:   
                    960:   while(!abort)
                    961:     {
                    962:       if(!HTQueue_isEmpty(mr->queue))
                    963:        {
                    964:          HTRequest *newreq;
                    965:          
                    966:          HyperDoc *nhd = (HyperDoc *)HTQueue_headOfQueue(mr->queue);
                    967:          
                    968:          if(nhd)
                    969:            {
                    970:              char *uri = HTAnchor_address((HTAnchor *)nhd->anchor);
                    971:              HTQueue_dequeue(mr->queue); (mr->cq)--;
                    972: 
                    973:              nfinger = Finger_new(mr, nhd->anchor, nhd->method); 
                    974:              
                    975:              newreq = nfinger->request;
                    976: 
1.82    ! frystyk   977:              if(SHOW_QUIET(mr))  HTPrint("Request from QUEUE  %s\n",uri);
1.75      frystyk   978:              HT_FREE(uri);
1.82    ! frystyk   979:              if(SHOW_QUIET(mr)) HTPrint("%d elements in queue \n", mr->cq);
1.75      frystyk   980: 
                    981:              HTRequest_setParent(newreq,get_last_parent(nhd->anchor));
                    982: 
1.76      frystyk   983:              /* @@@ Should be done using a timer and not sleep! @@@ */
                    984: #if 0
1.75      frystyk   985:              if(mr->waits)
                    986:                  sleep(mr->waits);
1.76      frystyk   987: #endif
1.75      frystyk   988:              
                    989:              if (HTLoadAnchor((HTAnchor *)nhd->anchor , newreq) != YES) 
                    990:                {
1.82    ! frystyk   991:                  if (SHOW_QUIET(mr)) HTPrint("not tested!\n");
1.75      frystyk   992:                  Finger_delete(nfinger);
                    993:                }
                    994:            }
                    995:          else
                    996:            abort = YES;
                    997:        }
                    998:       else
                    999:        abort = YES;
                   1000:     }
                   1001: 
1.82    ! frystyk  1002:   if(SHOW_QUIET(mr)) HTPrint("Queue size: %d \n", mr->cq);
1.75      frystyk  1003: 
                   1004:     if (mr->cnt <= 0 || (abort && (mr->flags & MR_PREEMPTIVE)))
                   1005:       {
                   1006:        if(mr->cnt > 0)
1.82    ! frystyk  1007:          if(SHOW_QUIET(mr)) HTPrint("%d requests were not served\n", mr->cnt);
1.75      frystyk  1008: 
1.82    ! frystyk  1009:        if (SHOW_QUIET(mr)) HTPrint("             Everything is finished...\n");
1.46      eric     1010:        Cleanup(mr, 0);                 /* No way back from here */
1.75      frystyk  1011:       }
1.1       frystyk  1012: }
                   1013: 
                   1014: /* ------------------------------------------------------------------------- */
                   1015: /*                             HTEXT INTERFACE                              */
                   1016: /* ------------------------------------------------------------------------- */
                   1017: 
1.80      frystyk  1018: PUBLIC BOOL Robot_registerHTMLParser (void)
                   1019: {
                   1020:     HText_registerCDCallback(RHText_new, RHText_delete);
                   1021:     HText_registerLinkCallback(RHText_foundLink);
                   1022:     return YES;
                   1023: }
                   1024: 
                   1025: PRIVATE HText * RHText_new (HTRequest * request, HTParentAnchor * anchor,
                   1026:                            HTStream * stream)
1.1       frystyk  1027: {
                   1028:     HText * me;
1.34      eric     1029:     Finger * finger = (Finger *) HTRequest_context(request);
                   1030:     Robot * mr = finger->robot;
1.65      frystyk  1031:     char * robots = NULL;
                   1032: 
1.14      frystyk  1033:     if ((me = (HText *) HT_CALLOC(1, sizeof(HText))) == NULL)
                   1034:        HT_OUTOFMEM("HText_new2");
1.4       frystyk  1035: 
                   1036:     /* Bind the HText object together with the Request Object */
1.1       frystyk  1037:     me->request = request;
1.65      frystyk  1038:     me->follow = YES;
                   1039: 
                   1040:     /* Check to see if we have any meta tags */
1.77      frystyk  1041:     if (!(mr->flags & MR_NOMETATAGS) && (robots = HTAnchor_robots(anchor)) != NULL) {
1.65      frystyk  1042:        char * strval = NULL;
                   1043:        char * ptr = NULL;
                   1044:        char * token = NULL;
                   1045:        StrAllocCopy(strval, robots);
                   1046:        ptr = strval;
                   1047:        while ((token = HTNextField(&ptr)) != NULL) {
                   1048:            if (!strcasecomp(token, "nofollow")) {
                   1049:                me->follow = NO;
                   1050:                break;
                   1051:            }
                   1052:        }
                   1053:        HT_FREE(strval);
                   1054:     }
1.4       frystyk  1055: 
                   1056:     /* Add this HyperDoc object to our list */
                   1057:     if (!mr->htext) mr->htext = HTList_new();
                   1058:     HTList_addObject(mr->htext, (void *) me);
1.1       frystyk  1059:     return me;
                   1060: }
                   1061: 
1.80      frystyk  1062: PRIVATE BOOL RHText_delete (HText * me) {
1.81      frystyk  1063:     if (me) {
                   1064:        HT_FREE(me);
                   1065:        return YES;
                   1066:     }
                   1067:     return NO;
1.4       frystyk  1068: }
                   1069: 
1.80      frystyk  1070: PRIVATE void RHText_foundAnchor (HText * text, HTChildAnchor * anchor)
1.1       frystyk  1071: {
                   1072:     if (text && anchor) {
1.34      eric     1073:        Finger * finger = (Finger *) HTRequest_context(text->request);
                   1074:        Robot * mr = finger->robot;
1.1       frystyk  1075:        HTAnchor * dest = HTAnchor_followMainLink((HTAnchor *) anchor);
                   1076:        HTParentAnchor * dest_parent = HTAnchor_parent(dest);
1.7       frystyk  1077:        char * uri = HTAnchor_address((HTAnchor *) dest_parent);
1.1       frystyk  1078:        HyperDoc * hd = HTAnchor_document(dest_parent);
1.60      frystyk  1079:        HTParentAnchor * referer = HTRequest_anchor(text->request);
1.65      frystyk  1080:        BOOL match = text->follow;
1.58      frystyk  1081:        BOOL check = NO;
1.1       frystyk  1082: 
1.75      frystyk  1083:        /* These are new variables */
                   1084:        HyperDoc * nhd = NULL;
                   1085:        BOOL follow = YES;
                   1086: 
                   1087:        /* These three variables were moved */
                   1088:        /*HTParentAnchor * last_anchor = HTRequest_parent(text->request);*/
                   1089:        HTParentAnchor * last_anchor = HTRequest_anchor(text->request);
                   1090:        HyperDoc * last_doc = HTAnchor_document(last_anchor);
                   1091:        int depth = last_doc ? last_doc->depth+1 : 0;
                   1092: 
1.55      frystyk  1093:        if (!uri) return;
1.82    ! frystyk  1094:        if (SHOW_QUIET(mr)) HTPrint("Robot....... Found `%s\' - \n", uri ? uri : "NULL\n");
1.55      frystyk  1095: 
                   1096:         if (hd) {
1.82    ! frystyk  1097:            if (SHOW_QUIET(mr)) HTPrint("............ Already checked\n");
1.55      frystyk  1098:             hd->hits++;
1.68      frystyk  1099: #ifdef HT_MYSQL
                   1100:            if (mr->sqllog) {
                   1101:                char * ref_addr = HTAnchor_address((HTAnchor *) referer);
                   1102:                if (ref_addr) {
                   1103:                    HTSQLLog_addLinkRelationship(mr->sqllog, ref_addr, uri,
                   1104:                                                 "referer", NULL);
                   1105:                    HT_FREE(ref_addr);
                   1106:                }
                   1107:            }
                   1108: #endif
1.58      frystyk  1109:            HT_FREE(uri);
                   1110:            return;
                   1111:        }
1.70      frystyk  1112: 
1.58      frystyk  1113:        /* Check for prefix match */
1.65      frystyk  1114:        if (match && mr->prefix) {
                   1115:            match = HTStrMatch(mr->prefix, uri) ? YES : NO;
                   1116:        }
1.58      frystyk  1117: 
                   1118: #ifdef HT_POSIX_REGEX
1.69      frystyk  1119:        /*
                   1120:        **  Check for any regular expression. The include may override
                   1121:        **  the prefix matching
                   1122:        */
                   1123:        if (mr->include) {
1.58      frystyk  1124:            match = regexec(mr->include, uri, 0, NULL, 0) ? NO : YES;
                   1125:        }
1.75      frystyk  1126:        if (match && mr->exc_robot) {
                   1127:            match = regexec(mr->exc_robot, uri, 0, NULL, 0) ? YES : NO;
                   1128:        }
1.58      frystyk  1129:        if (match && mr->exclude) {
                   1130:            match = regexec(mr->exclude, uri, 0, NULL, 0) ? YES : NO;
                   1131:        }
                   1132:        if (match && mr->check) {
                   1133:            check = regexec(mr->check, uri, 0, NULL, 0) ? NO : YES;
                   1134:        }
                   1135: #endif
1.75      frystyk  1136:        if(uri && test_for_blank_spaces(uri))
                   1137:          follow = NO;
                   1138:        else if (mr->ndoc == 0) /* Number of Documents is reached */
                   1139:          follow = NO;
                   1140: 
                   1141:        /* Test whether we already have a hyperdoc for this document */
                   1142:        if(!hd && dest_parent)
                   1143:          {
                   1144:            nhd = HyperDoc_new(mr, dest_parent, depth);
                   1145:            mr->cdepth[depth]++;
                   1146:          }
1.58      frystyk  1147: 
                   1148:        /* Test whether we already have a hyperdoc for this document */
1.78      frystyk  1149:         if (mr->flags & MR_LINK && match && dest_parent && follow && !hd) {
                   1150:            if (mr->flags & MR_BFS) {
                   1151:                nhd->method = METHOD_HEAD;
                   1152:                HTQueue_enqueue(mr->queue, (void *) nhd);
                   1153:                (mr->cq)++;
                   1154:                if(mr->ndoc > 0) mr->ndoc--;
                   1155:            } else {
                   1156:                Finger * newfinger = Finger_new(mr, dest_parent, METHOD_GET);
                   1157:                HTRequest * newreq = newfinger->request;
                   1158:                HTRequest_setParent(newreq, referer);
                   1159:                if (check || depth >= mr->depth) {
1.82    ! frystyk  1160:                    if (SHOW_QUIET(mr)) HTPrint("loading at depth %d using HEAD\n", depth);
1.78      frystyk  1161:                    HTRequest_setMethod(newreq, METHOD_HEAD);
                   1162:                } else {
1.82    ! frystyk  1163:                    if (SHOW_QUIET(mr)) HTPrint("loading at depth %d\n", depth);
1.78      frystyk  1164:                }
                   1165:                if (HTLoadAnchor((HTAnchor *) dest_parent, newreq) != YES) {
1.82    ! frystyk  1166:                    if (SHOW_QUIET(mr)) HTPrint("not tested!\n");
1.78      frystyk  1167:                    Finger_delete(newfinger);
                   1168:                }
                   1169:            }
1.75      frystyk  1170: 
1.7       frystyk  1171:        } else {
1.82    ! frystyk  1172:            if (SHOW_QUIET(mr)) HTPrint("............ does not fulfill constraints\n");
1.68      frystyk  1173: #ifdef HT_MYSQL
                   1174:            if (mr->reject || mr->sqllog) {
                   1175: #else  
1.60      frystyk  1176:            if (mr->reject) {
1.68      frystyk  1177: #endif
1.60      frystyk  1178:                if (referer) {
                   1179:                    char * ref_addr = HTAnchor_address((HTAnchor *) referer);
1.68      frystyk  1180:                    if (mr->reject && ref_addr)
                   1181:                        HTLog_addText(mr->reject, "%s --> %s\n", ref_addr, uri);
                   1182: #ifdef HT_MYSQL
                   1183:                    if (mr->sqllog && mr->sqlexternals && ref_addr)
                   1184:                        HTSQLLog_addLinkRelationship(mr->sqllog,
                   1185:                                                     ref_addr, uri,
                   1186:                                                     "referer", NULL);
                   1187: #endif
                   1188: 
1.60      frystyk  1189:                    HT_FREE(ref_addr);
                   1190:                }
                   1191:            }
1.2       frystyk  1192:        }
1.11      frystyk  1193:        HT_FREE(uri);
1.2       frystyk  1194:     }
                   1195: }
                   1196: 
1.80      frystyk  1197: PRIVATE void RHText_foundImage (HText * text, HTChildAnchor * anchor,
                   1198:                                const char *alt, const char * align, BOOL isMap)
1.2       frystyk  1199: {
                   1200:     if (text && anchor) {
1.34      eric     1201:        Finger * finger = (Finger *) HTRequest_context(text->request);
                   1202:        Robot * mr = finger->robot;
1.75      frystyk  1203: 
1.59      frystyk  1204:        if (mr->flags & MR_IMG) {
1.60      frystyk  1205:            HTAnchor * dest = HTAnchor_followMainLink((HTAnchor *) anchor);
                   1206:            HTParentAnchor * dest_parent = HTAnchor_parent(dest);
                   1207:            char * uri = HTAnchor_address((HTAnchor *) dest_parent);
                   1208:            HyperDoc * hd = HTAnchor_document(dest_parent);
                   1209:            HTParentAnchor * referer = HTRequest_anchor(text->request);
1.59      frystyk  1210:            BOOL match = YES;
                   1211: 
1.72      frystyk  1212:            if (!uri) return;
1.59      frystyk  1213:            if (hd) {
1.82    ! frystyk  1214:                if (SHOW_QUIET(mr)) HTPrint("............ Already checked\n");
1.59      frystyk  1215:                hd->hits++;
1.68      frystyk  1216: #ifdef HT_MYSQL
                   1217:                if (mr->sqllog) {
                   1218:                    char * ref_addr = HTAnchor_address((HTAnchor *) referer);
                   1219:                    if (ref_addr) {
                   1220:                        HTSQLLog_addLinkRelationship(mr->sqllog,
                   1221:                                                     ref_addr, uri,
                   1222:                                                     "image", alt);
                   1223:                        HT_FREE(ref_addr);
                   1224:                    }
                   1225:                }
                   1226: #endif
1.11      frystyk  1227:                HT_FREE(uri);
1.59      frystyk  1228:                return;
1.2       frystyk  1229:            }
1.59      frystyk  1230: 
                   1231:            /* Check for prefix match */
                   1232:            if (mr->img_prefix) match = HTStrMatch(mr->img_prefix, uri) ? YES : NO;
                   1233: 
1.79      br334    1234: #ifdef HT_POSIX_REGEX
                   1235:        /*
                   1236:        **  Check for any regular expression. The include may override
                   1237:        **  the prefix matching
                   1238:        */
                   1239:        if (mr->include) {
                   1240:            match = regexec(mr->include, uri, 0, NULL, 0) ? NO : YES;
                   1241:        }
                   1242:        if (match && mr->exc_robot) {
                   1243:            match = regexec(mr->exc_robot, uri, 0, NULL, 0) ? YES : NO;
                   1244:        }
                   1245:        if (match && mr->exclude) {
                   1246:            match = regexec(mr->exclude, uri, 0, NULL, 0) ? YES : NO;
                   1247:        }
                   1248: #endif
1.59      frystyk  1249:            /* Test whether we already have a hyperdoc for this document */
                   1250:            if (match && dest) {
1.60      frystyk  1251:                Finger * newfinger = Finger_new(mr, dest_parent,
1.59      frystyk  1252:                                                mr->flags & MR_SAVE ?
                   1253:                                                METHOD_GET : METHOD_HEAD);
                   1254:                HTRequest * newreq = newfinger->request;
1.60      frystyk  1255:                HyperDoc_new(mr, dest_parent, 1);
                   1256:                HTRequest_setParent(newreq, referer);
                   1257: 
                   1258:                /* Check whether we should report missing ALT tags */
                   1259:                if (mr->noalttag && (alt==NULL || *alt=='\0')) {
                   1260:                    if (referer) {
                   1261:                        char * ref_addr = HTAnchor_address((HTAnchor *) referer);
                   1262:                        if (ref_addr) HTLog_addText(mr->noalttag, "%s --> %s\n", ref_addr, uri);
                   1263:                        HT_FREE(ref_addr);
                   1264:                    }
                   1265:                }
                   1266:                
1.82    ! frystyk  1267:                if (SHOW_QUIET(mr)) HTPrint("Robot....... Checking Image `%s\'\n", uri);
1.59      frystyk  1268:                if (HTLoadAnchor((HTAnchor *) dest, newreq) != YES) {
1.82    ! frystyk  1269:                    if (SHOW_QUIET(mr)) HTPrint("Robot....... Image not tested!\n");
1.59      frystyk  1270:                    Finger_delete(newfinger);
                   1271:                }
                   1272:            } else {
1.82    ! frystyk  1273:                if (SHOW_QUIET(mr)) HTPrint("............ does not fulfill constraints\n");
1.68      frystyk  1274: #ifdef HT_MYSQL
                   1275:                if (mr->reject || mr->sqllog) {
                   1276: #else  
1.60      frystyk  1277:                if (mr->reject) {
1.68      frystyk  1278: #endif
1.60      frystyk  1279:                    if (referer) {
                   1280:                        char * ref_addr = HTAnchor_address((HTAnchor *) referer);
1.68      frystyk  1281:                        if (mr->reject && ref_addr)
                   1282:                            HTLog_addText(mr->reject, "%s --> %s\n", ref_addr, uri);
                   1283: #ifdef HT_MYSQL
                   1284:                        if (mr->sqllog && mr->sqlexternals && ref_addr)
                   1285:                            HTSQLLog_addLinkRelationship(mr->sqllog,
                   1286:                                                         ref_addr, uri,
                   1287:                                                         "image", alt);
                   1288: #endif
                   1289: 
1.60      frystyk  1290:                        HT_FREE(ref_addr);
                   1291:                    }
                   1292:                }
1.1       frystyk  1293:            }
1.59      frystyk  1294:            HT_FREE(uri);
1.72      frystyk  1295:        }
                   1296:     }
                   1297: }
                   1298: 
1.80      frystyk  1299: PRIVATE void RHText_foundLink (HText * text,
                   1300:                               int element_number, int attribute_number,
                   1301:                               HTChildAnchor * anchor,
                   1302:                               const BOOL * present, const char ** value)
1.72      frystyk  1303: {
                   1304:     if (text && anchor) {
                   1305:        Finger * finger = (Finger *) HTRequest_context(text->request);
                   1306:        Robot * mr = finger->robot;
                   1307:        if (SHOW_QUIET(mr))
1.82    ! frystyk  1308:            HTPrint("Robot....... Received element %d, attribute %d with anchor %p\n",
1.80      frystyk  1309:                    element_number, attribute_number, anchor);
                   1310:        if ((element_number==HTML_IMG && attribute_number==HTML_IMG_SRC) || 
                   1311:            (element_number==HTML_BODY && attribute_number==HTML_BODY_BACKGROUND))
                   1312:            RHText_foundImage(text, anchor, NULL, NULL, NO);
                   1313:        else
                   1314:            RHText_foundAnchor(text, anchor);
1.72      frystyk  1315:     }
                   1316: }
                   1317: 
1.80      frystyk  1318: PUBLIC char * get_robots_txt(char * uri)
1.48      frystyk  1319: {
1.75      frystyk  1320:   char *str = NULL;
                   1321:   HTChunk * chunk;
                   1322:   HTParentAnchor *anchor = HTAnchor_parent(HTAnchor_findAddress(uri));
                   1323:   HTRequest *request = HTRequest_new();
                   1324:   HTRequest_setOutputFormat(request, WWW_SOURCE);
                   1325:   HTRequest_setPreemptive(request, YES);
                   1326:   HTRequest_setMethod(request, METHOD_GET);
                   1327:   chunk = HTLoadAnchorToChunk ((HTAnchor *)anchor, request);
                   1328:   str = HTChunk_toCString(chunk);
                   1329:   HTRequest_delete(request);
                   1330:   return str;
1.48      frystyk  1331: }
                   1332: 

Webmaster