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

1.75      frystyk     1: /*
1.84    ! frystyk     2: **     @(#) $Id: HTRobot.c,v 1.83 1999/02/23 17:53:30 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 */
1.83      frystyk   694: #if 0
                    695:        if (mr->cdepth) FT_FREE(mr->cdepth);
                    696: #endif
                    697: 
1.75      frystyk   698:        if(mr->furl) HT_FREE(mr->furl);
                    699: 
1.58      frystyk   700: #ifdef HT_POSIX_REGEX
1.62      frystyk   701:        if (mr->include) {
                    702:            regfree(mr->include);
                    703:            HT_FREE(mr->include);
                    704:        }
                    705:        if (mr->exclude) {
                    706:            regfree(mr->exclude);
                    707:            HT_FREE(mr->exclude);
                    708:        }
1.75      frystyk   709:        if (mr->exc_robot) {
                    710:            regfree(mr->exc_robot);
                    711:            HT_FREE(mr->exc_robot);
                    712:        }
1.62      frystyk   713:        if (mr->check) {
                    714:            regfree(mr->check);
                    715:            HT_FREE(mr->check);
1.58      frystyk   716:        }
                    717: #endif
                    718: 
1.68      frystyk   719: #ifdef HT_MYSQL
                    720:        if (mr->sqllog) {
                    721:            HTSQLLog_close(mr->sqllog);
                    722:            mr->sqllog = NULL;
                    723:        }
                    724: #endif
                    725: 
1.81      frystyk   726:        if (mr->queue) HTQueue_delete(mr->queue);
1.62      frystyk   727:        HT_FREE(mr->cwd);
                    728:        HT_FREE(mr->prefix);
                    729:        HT_FREE(mr->img_prefix);
                    730:        HT_FREE(mr);
1.1       frystyk   731:        return YES;
                    732:     }
                    733:     return NO;
                    734: }
                    735: 
1.2       frystyk   736: /*
1.34      eric      737: **  This function creates a new finger object and initializes it with a new request
1.2       frystyk   738: */
1.75      frystyk   739: PUBLIC Finger * Finger_new (Robot * robot, HTParentAnchor * dest, HTMethod method)
1.2       frystyk   740: {
1.34      eric      741:     Finger * me;
                    742:     HTRequest * request = HTRequest_new();
                    743:     if ((me = (Finger *) HT_CALLOC(1, sizeof(Finger))) == NULL)
                    744:        HT_OUTOFMEM("Finger_new");
                    745:     me->robot = robot;
                    746:     me->request = request;
                    747:     me->dest = dest;
                    748:     HTList_addObject(robot->fingers, (void *)me);
                    749: 
1.48      frystyk   750:     /* Set the context for this request */
1.34      eric      751:     HTRequest_setContext (request, me);
1.48      frystyk   752: 
                    753:     /* Check the various flags to customize the request */
                    754:     if (robot->flags & MR_PREEMPTIVE)
                    755:        HTRequest_setPreemptive(request, YES);
                    756:     if (robot->flags & MR_VALIDATE)
                    757:        HTRequest_setReloadMode(request, HT_CACHE_VALIDATE);
                    758:     if (robot->flags & MR_END_VALIDATE)
                    759:        HTRequest_setReloadMode(request, HT_CACHE_END_VALIDATE);
                    760: 
                    761:     /* We wanna make sure that we are sending a Host header (default) */
1.34      eric      762:     HTRequest_addRqHd(request, HT_C_HOST);
1.48      frystyk   763: 
                    764:     /* Set the method for this request */
1.34      eric      765:     HTRequest_setMethod(request, method);
                    766:     robot->cnt++;
                    767:     return me;
1.2       frystyk   768: }
                    769: 
1.34      eric      770: PRIVATE int Finger_delete (Finger * me)
1.2       frystyk   771: {
1.34      eric      772:     HTList_removeObject(me->robot->fingers, (void *)me);
                    773:     me->robot->cnt--;
1.37      frystyk   774: 
                    775:     /*
                    776:     **  If we are down at one request then flush the output buffer
                    777:     */
                    778:     if (me->request) {
                    779:        if (me->robot->cnt == 1) HTRequest_forceFlush(me->request);
1.34      eric      780:        HTRequest_delete(me->request);
1.37      frystyk   781:     }
                    782: 
                    783:     /*
                    784:     **  Delete the request and free myself
                    785:     */
1.34      eric      786:     HT_FREE(me);
                    787:     return YES;
1.2       frystyk   788: }
                    789: 
                    790: /*
                    791: **  Cleanup and make sure we close all connections including the persistent
                    792: **  ones
                    793: */
1.75      frystyk   794: PUBLIC void Cleanup (Robot * me, int status)
1.1       frystyk   795: {
1.84    ! frystyk   796:     /*
        !           797:     **  First we clean up the robot itself and calculate the various
        !           798:     **  statistics. This can actually take some time as a lot of data
        !           799:     **  has to be manipulated
        !           800:     */
        !           801:     Robot_delete(me);
        !           802: 
        !           803:     /*
        !           804:     **  Then we shut down libwww
        !           805:     */
1.81      frystyk   806:     HTProfile_delete();
1.84    ! frystyk   807: 
1.50      frystyk   808: #ifdef HT_MEMLOG
1.39      eric      809:     HTMemLog_close();
1.47      frystyk   810: #endif
                    811: 
1.1       frystyk   812: #ifdef VMS
                    813:     exit(status ? status : 1);
                    814: #else
                    815:     exit(status ? status : 0);
                    816: #endif
                    817: }
                    818: 
1.58      frystyk   819: #ifdef HT_POSIX_REGEX
                    820: PRIVATE char * get_regerror (int errcode, regex_t * compiled)
                    821: {
                    822:     size_t length = regerror (errcode, compiled, NULL, 0);
                    823:     char * str = NULL;
                    824:     if ((str = (char *) HT_MALLOC(length+1)) == NULL)
                    825:        HT_OUTOFMEM("get_regerror");
                    826:     (void) regerror (errcode, compiled, str, length);
                    827:     return str;
                    828: }
                    829: 
1.75      frystyk   830: PUBLIC regex_t * get_regtype (Robot * mr, const char * regex_str, int cflags)
1.58      frystyk   831: {
                    832:     regex_t * regex = NULL;
                    833:     if (regex_str && *regex_str) {
                    834:        int status;
                    835:        if ((regex = (regex_t *) HT_CALLOC(1, sizeof(regex_t))) == NULL)
                    836:            HT_OUTOFMEM("get_regtype");
1.60      frystyk   837:        if ((status = regcomp(regex, regex_str, cflags))) {
1.58      frystyk   838:            char * err_msg = get_regerror(status, regex);
1.62      frystyk   839:            if (SHOW_REAL_QUIET(mr))
1.82      frystyk   840:                HTPrint("Regular expression error: %s\n", err_msg);
1.58      frystyk   841:            HT_FREE(err_msg);
                    842:            Cleanup(mr, -1);
                    843:        }
                    844:     }
                    845:     return regex;
                    846: }
                    847: #endif
                    848: 
1.75      frystyk   849: PUBLIC void VersionInfo (void)
1.1       frystyk   850: {
1.82      frystyk   851:     HTPrint("\nW3C OpenSource Software");
                    852:     HTPrint("\n-----------------------\n\n");
                    853:     HTPrint("\tWebbot version %s\n", APP_VERSION);
                    854:     HTPrint("\tusing the W3C libwww library version %s.\n\n",HTLib_version());
                    855:     HTPrint("\tSee \"%s\" for help\n", COMMAND_LINE);
                    856:     HTPrint("\tSee \"http://www.w3.org/Robot/User/\" for user information\n");
                    857:     HTPrint("\tSee \"http://www.w3.org/Robot/\" for general information\n\n");
                    858:     HTPrint("\tPlease send feedback to the <www-lib@w3.org> mailing list,\n");
                    859:     HTPrint("\tsee \"http://www.w3.org/Library/#Forums\" for details\n\n");
1.1       frystyk   860: }
                    861: 
                    862: /*     terminate_handler
                    863: **     -----------------
1.2       frystyk   864: **     This function is registered to handle the result of the request.
                    865: **     If no more requests are pending then terminate program
1.1       frystyk   866: */
1.75      frystyk   867: PUBLIC int terminate_handler (HTRequest * request, HTResponse * response,
1.32      frystyk   868:                               void * param, int status) 
1.1       frystyk   869: {
1.34      eric      870:     Finger * finger = (Finger *) HTRequest_context(request);
1.46      eric      871:     Robot * mr = finger->robot;
1.82      frystyk   872:     if (SHOW_QUIET(mr)) HTPrint("Robot....... done with %s\n", HTAnchor_physical(finger->dest));
1.55      frystyk   873: 
1.68      frystyk   874: #ifdef HT_MYSQL
                    875:     if (mr->sqllog) HTSQLLog_addEntry(mr->sqllog, request, status);
                    876: #endif
                    877: 
1.58      frystyk   878:     /* Check if negotiated resource and whether we should log that*/
                    879:     if (mr->conneg) {
                    880:        HTAssocList * cur = HTResponse_variant(response);
                    881:        if (cur) {
                    882:            BOOL first = YES;
                    883:            HTChunk * buffer = HTChunk_new(128);
                    884:            char * uri = HTAnchor_address((HTAnchor *) finger->dest);
                    885:            HTAssoc * pres;
1.60      frystyk   886:            HTChunk_puts(buffer, uri);
1.58      frystyk   887:            while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
                    888:                char * value = HTAssoc_value(pres);
                    889:                if (first) {
1.60      frystyk   890:                    HTChunk_puts(buffer, "\t(");
1.58      frystyk   891:                    first = NO;
                    892:                } else
                    893:                    HTChunk_puts(buffer, ", ");
                    894: 
                    895:                /* Output the name */
                    896:                HTChunk_puts(buffer, HTAssoc_name(pres));
                    897: 
                    898:                /* Only output the value if not empty string */
1.60      frystyk   899:                if (value && *value) {
1.58      frystyk   900:                    HTChunk_puts(buffer, "=");
                    901:                    HTChunk_puts(buffer, value);
                    902:                }
                    903:            }
1.60      frystyk   904:            if (!first) HTChunk_puts(buffer, ")");
                    905:            HTLog_addLine(mr->conneg, HTChunk_data(buffer));
1.58      frystyk   906:            HTChunk_delete(buffer);
                    907:            HT_FREE(uri);
                    908:        }
                    909:     }
                    910: 
1.55      frystyk   911:     /* Count the amount of body data that we have read */
1.59      frystyk   912:     if (HTRequest_method(request) == METHOD_GET) {
                    913:        int length = HTAnchor_length(HTRequest_anchor(request));
                    914:        if (length > 0) mr->get_bytes += length;
                    915:        mr->get_docs++;
                    916:     } else if (HTRequest_method(request) == METHOD_HEAD) {
1.56      frystyk   917:        int length = HTAnchor_length(HTRequest_anchor(request));
1.59      frystyk   918:        if (length > 0) mr->head_bytes += length;
                    919:        mr->head_docs++;
                    920:     } else {
                    921:        mr->other_docs++;
1.55      frystyk   922:     }
                    923: 
1.78      frystyk   924:     if (!(mr->flags & MR_BFS)) {
                    925: 
                    926:        /* Delete this thread */
                    927:        Finger_delete(finger);
                    928: 
                    929:        /* Should we stop? */
                    930:        if (mr->cnt <= 0) {
1.82      frystyk   931:            if (SHOW_QUIET(mr)) HTPrint("             Everything is finished...\n");
1.78      frystyk   932:            Cleanup(mr, 0);                     /* No way back from here */
                    933:        }
                    934:     }
                    935: 
1.82      frystyk   936:     if (SHOW_QUIET(mr)) HTPrint("             %d outstanding request%s\n", mr->cnt, mr->cnt == 1 ? "" : "s");
1.75      frystyk   937:     return HT_OK;
                    938: 
                    939: }
                    940: PUBLIC int my_terminate_handler (HTRequest * request, HTResponse * response,
                    941:                               void * param, int status) 
                    942: {
                    943:     Finger * finger = (Finger *) HTRequest_context(request);
                    944:     Robot * mr = finger->robot;
                    945:     HTParentAnchor * dest = finger->dest;
                    946:     HyperDoc * hd = HTAnchor_document(dest);
                    947:     int depth = (hd ? hd->depth : -1);
                    948: 
                    949:     if (hd) set_error_state_hyperdoc(hd,request);
                    950:       
                    951:     if(hd && (HTRequest_method(request)== METHOD_HEAD) && 
                    952:        (depth < mr->depth))
                    953:       {
                    954:        hd->method = METHOD_GET;
                    955:        HTQueue_append(mr->queue, (void *)hd); (mr->cq)++;
                    956:       }
1.58      frystyk   957: 
1.34      eric      958:     Finger_delete(finger);
1.55      frystyk   959: 
1.75      frystyk   960:     if(!(mr->flags & MR_PREEMPTIVE))
                    961:       Serving_queue(mr);
                    962: 
                    963:     return HT_OK;
                    964: }
                    965: 
                    966: 
                    967: PUBLIC void Serving_queue(Robot *mr)
                    968: {
                    969:   BOOL abort = NO;
                    970:   Finger *nfinger;
                    971:   
                    972:   while(!abort)
                    973:     {
                    974:       if(!HTQueue_isEmpty(mr->queue))
                    975:        {
                    976:          HTRequest *newreq;
                    977:          
                    978:          HyperDoc *nhd = (HyperDoc *)HTQueue_headOfQueue(mr->queue);
                    979:          
                    980:          if(nhd)
                    981:            {
                    982:              char *uri = HTAnchor_address((HTAnchor *)nhd->anchor);
                    983:              HTQueue_dequeue(mr->queue); (mr->cq)--;
                    984: 
                    985:              nfinger = Finger_new(mr, nhd->anchor, nhd->method); 
                    986:              
                    987:              newreq = nfinger->request;
                    988: 
1.82      frystyk   989:              if(SHOW_QUIET(mr))  HTPrint("Request from QUEUE  %s\n",uri);
1.75      frystyk   990:              HT_FREE(uri);
1.82      frystyk   991:              if(SHOW_QUIET(mr)) HTPrint("%d elements in queue \n", mr->cq);
1.75      frystyk   992: 
                    993:              HTRequest_setParent(newreq,get_last_parent(nhd->anchor));
                    994: 
1.76      frystyk   995:              /* @@@ Should be done using a timer and not sleep! @@@ */
                    996: #if 0
1.75      frystyk   997:              if(mr->waits)
                    998:                  sleep(mr->waits);
1.76      frystyk   999: #endif
1.75      frystyk  1000:              
                   1001:              if (HTLoadAnchor((HTAnchor *)nhd->anchor , newreq) != YES) 
                   1002:                {
1.82      frystyk  1003:                  if (SHOW_QUIET(mr)) HTPrint("not tested!\n");
1.75      frystyk  1004:                  Finger_delete(nfinger);
                   1005:                }
                   1006:            }
                   1007:          else
                   1008:            abort = YES;
                   1009:        }
                   1010:       else
                   1011:        abort = YES;
                   1012:     }
                   1013: 
1.82      frystyk  1014:   if(SHOW_QUIET(mr)) HTPrint("Queue size: %d \n", mr->cq);
1.75      frystyk  1015: 
                   1016:     if (mr->cnt <= 0 || (abort && (mr->flags & MR_PREEMPTIVE)))
                   1017:       {
                   1018:        if(mr->cnt > 0)
1.82      frystyk  1019:          if(SHOW_QUIET(mr)) HTPrint("%d requests were not served\n", mr->cnt);
1.75      frystyk  1020: 
1.82      frystyk  1021:        if (SHOW_QUIET(mr)) HTPrint("             Everything is finished...\n");
1.46      eric     1022:        Cleanup(mr, 0);                 /* No way back from here */
1.75      frystyk  1023:       }
1.1       frystyk  1024: }
                   1025: 
                   1026: /* ------------------------------------------------------------------------- */
                   1027: /*                             HTEXT INTERFACE                              */
                   1028: /* ------------------------------------------------------------------------- */
                   1029: 
1.80      frystyk  1030: PUBLIC BOOL Robot_registerHTMLParser (void)
                   1031: {
                   1032:     HText_registerCDCallback(RHText_new, RHText_delete);
                   1033:     HText_registerLinkCallback(RHText_foundLink);
                   1034:     return YES;
                   1035: }
                   1036: 
                   1037: PRIVATE HText * RHText_new (HTRequest * request, HTParentAnchor * anchor,
                   1038:                            HTStream * stream)
1.1       frystyk  1039: {
                   1040:     HText * me;
1.34      eric     1041:     Finger * finger = (Finger *) HTRequest_context(request);
                   1042:     Robot * mr = finger->robot;
1.65      frystyk  1043:     char * robots = NULL;
                   1044: 
1.14      frystyk  1045:     if ((me = (HText *) HT_CALLOC(1, sizeof(HText))) == NULL)
                   1046:        HT_OUTOFMEM("HText_new2");
1.4       frystyk  1047: 
                   1048:     /* Bind the HText object together with the Request Object */
1.1       frystyk  1049:     me->request = request;
1.65      frystyk  1050:     me->follow = YES;
                   1051: 
                   1052:     /* Check to see if we have any meta tags */
1.77      frystyk  1053:     if (!(mr->flags & MR_NOMETATAGS) && (robots = HTAnchor_robots(anchor)) != NULL) {
1.65      frystyk  1054:        char * strval = NULL;
                   1055:        char * ptr = NULL;
                   1056:        char * token = NULL;
                   1057:        StrAllocCopy(strval, robots);
                   1058:        ptr = strval;
                   1059:        while ((token = HTNextField(&ptr)) != NULL) {
                   1060:            if (!strcasecomp(token, "nofollow")) {
                   1061:                me->follow = NO;
                   1062:                break;
                   1063:            }
                   1064:        }
                   1065:        HT_FREE(strval);
                   1066:     }
1.4       frystyk  1067: 
                   1068:     /* Add this HyperDoc object to our list */
                   1069:     if (!mr->htext) mr->htext = HTList_new();
                   1070:     HTList_addObject(mr->htext, (void *) me);
1.1       frystyk  1071:     return me;
                   1072: }
                   1073: 
1.80      frystyk  1074: PRIVATE BOOL RHText_delete (HText * me) {
1.81      frystyk  1075:     if (me) {
                   1076:        HT_FREE(me);
                   1077:        return YES;
                   1078:     }
                   1079:     return NO;
1.4       frystyk  1080: }
                   1081: 
1.80      frystyk  1082: PRIVATE void RHText_foundAnchor (HText * text, HTChildAnchor * anchor)
1.1       frystyk  1083: {
                   1084:     if (text && anchor) {
1.34      eric     1085:        Finger * finger = (Finger *) HTRequest_context(text->request);
                   1086:        Robot * mr = finger->robot;
1.1       frystyk  1087:        HTAnchor * dest = HTAnchor_followMainLink((HTAnchor *) anchor);
                   1088:        HTParentAnchor * dest_parent = HTAnchor_parent(dest);
1.7       frystyk  1089:        char * uri = HTAnchor_address((HTAnchor *) dest_parent);
1.1       frystyk  1090:        HyperDoc * hd = HTAnchor_document(dest_parent);
1.60      frystyk  1091:        HTParentAnchor * referer = HTRequest_anchor(text->request);
1.65      frystyk  1092:        BOOL match = text->follow;
1.58      frystyk  1093:        BOOL check = NO;
1.1       frystyk  1094: 
1.75      frystyk  1095:        /* These are new variables */
                   1096:        HyperDoc * nhd = NULL;
                   1097:        BOOL follow = YES;
                   1098: 
                   1099:        /* These three variables were moved */
                   1100:        /*HTParentAnchor * last_anchor = HTRequest_parent(text->request);*/
                   1101:        HTParentAnchor * last_anchor = HTRequest_anchor(text->request);
                   1102:        HyperDoc * last_doc = HTAnchor_document(last_anchor);
                   1103:        int depth = last_doc ? last_doc->depth+1 : 0;
                   1104: 
1.55      frystyk  1105:        if (!uri) return;
1.82      frystyk  1106:        if (SHOW_QUIET(mr)) HTPrint("Robot....... Found `%s\' - \n", uri ? uri : "NULL\n");
1.55      frystyk  1107: 
                   1108:         if (hd) {
1.82      frystyk  1109:            if (SHOW_QUIET(mr)) HTPrint("............ Already checked\n");
1.55      frystyk  1110:             hd->hits++;
1.68      frystyk  1111: #ifdef HT_MYSQL
                   1112:            if (mr->sqllog) {
                   1113:                char * ref_addr = HTAnchor_address((HTAnchor *) referer);
                   1114:                if (ref_addr) {
                   1115:                    HTSQLLog_addLinkRelationship(mr->sqllog, ref_addr, uri,
                   1116:                                                 "referer", NULL);
                   1117:                    HT_FREE(ref_addr);
                   1118:                }
                   1119:            }
                   1120: #endif
1.58      frystyk  1121:            HT_FREE(uri);
                   1122:            return;
                   1123:        }
1.70      frystyk  1124: 
1.58      frystyk  1125:        /* Check for prefix match */
1.65      frystyk  1126:        if (match && mr->prefix) {
                   1127:            match = HTStrMatch(mr->prefix, uri) ? YES : NO;
                   1128:        }
1.58      frystyk  1129: 
                   1130: #ifdef HT_POSIX_REGEX
1.69      frystyk  1131:        /*
                   1132:        **  Check for any regular expression. The include may override
                   1133:        **  the prefix matching
                   1134:        */
                   1135:        if (mr->include) {
1.58      frystyk  1136:            match = regexec(mr->include, uri, 0, NULL, 0) ? NO : YES;
                   1137:        }
1.75      frystyk  1138:        if (match && mr->exc_robot) {
                   1139:            match = regexec(mr->exc_robot, uri, 0, NULL, 0) ? YES : NO;
                   1140:        }
1.58      frystyk  1141:        if (match && mr->exclude) {
                   1142:            match = regexec(mr->exclude, uri, 0, NULL, 0) ? YES : NO;
                   1143:        }
                   1144:        if (match && mr->check) {
                   1145:            check = regexec(mr->check, uri, 0, NULL, 0) ? NO : YES;
                   1146:        }
                   1147: #endif
1.75      frystyk  1148:        if(uri && test_for_blank_spaces(uri))
                   1149:          follow = NO;
                   1150:        else if (mr->ndoc == 0) /* Number of Documents is reached */
                   1151:          follow = NO;
                   1152: 
                   1153:        /* Test whether we already have a hyperdoc for this document */
                   1154:        if(!hd && dest_parent)
                   1155:          {
                   1156:            nhd = HyperDoc_new(mr, dest_parent, depth);
                   1157:            mr->cdepth[depth]++;
                   1158:          }
1.58      frystyk  1159: 
                   1160:        /* Test whether we already have a hyperdoc for this document */
1.78      frystyk  1161:         if (mr->flags & MR_LINK && match && dest_parent && follow && !hd) {
                   1162:            if (mr->flags & MR_BFS) {
                   1163:                nhd->method = METHOD_HEAD;
                   1164:                HTQueue_enqueue(mr->queue, (void *) nhd);
                   1165:                (mr->cq)++;
                   1166:                if(mr->ndoc > 0) mr->ndoc--;
                   1167:            } else {
                   1168:                Finger * newfinger = Finger_new(mr, dest_parent, METHOD_GET);
                   1169:                HTRequest * newreq = newfinger->request;
                   1170:                HTRequest_setParent(newreq, referer);
                   1171:                if (check || depth >= mr->depth) {
1.82      frystyk  1172:                    if (SHOW_QUIET(mr)) HTPrint("loading at depth %d using HEAD\n", depth);
1.78      frystyk  1173:                    HTRequest_setMethod(newreq, METHOD_HEAD);
                   1174:                } else {
1.82      frystyk  1175:                    if (SHOW_QUIET(mr)) HTPrint("loading at depth %d\n", depth);
1.78      frystyk  1176:                }
                   1177:                if (HTLoadAnchor((HTAnchor *) dest_parent, newreq) != YES) {
1.82      frystyk  1178:                    if (SHOW_QUIET(mr)) HTPrint("not tested!\n");
1.78      frystyk  1179:                    Finger_delete(newfinger);
                   1180:                }
                   1181:            }
1.75      frystyk  1182: 
1.7       frystyk  1183:        } else {
1.82      frystyk  1184:            if (SHOW_QUIET(mr)) HTPrint("............ does not fulfill constraints\n");
1.68      frystyk  1185: #ifdef HT_MYSQL
                   1186:            if (mr->reject || mr->sqllog) {
                   1187: #else  
1.60      frystyk  1188:            if (mr->reject) {
1.68      frystyk  1189: #endif
1.60      frystyk  1190:                if (referer) {
                   1191:                    char * ref_addr = HTAnchor_address((HTAnchor *) referer);
1.68      frystyk  1192:                    if (mr->reject && ref_addr)
                   1193:                        HTLog_addText(mr->reject, "%s --> %s\n", ref_addr, uri);
                   1194: #ifdef HT_MYSQL
                   1195:                    if (mr->sqllog && mr->sqlexternals && ref_addr)
                   1196:                        HTSQLLog_addLinkRelationship(mr->sqllog,
                   1197:                                                     ref_addr, uri,
                   1198:                                                     "referer", NULL);
                   1199: #endif
                   1200: 
1.60      frystyk  1201:                    HT_FREE(ref_addr);
                   1202:                }
                   1203:            }
1.2       frystyk  1204:        }
1.11      frystyk  1205:        HT_FREE(uri);
1.2       frystyk  1206:     }
                   1207: }
                   1208: 
1.80      frystyk  1209: PRIVATE void RHText_foundImage (HText * text, HTChildAnchor * anchor,
                   1210:                                const char *alt, const char * align, BOOL isMap)
1.2       frystyk  1211: {
                   1212:     if (text && anchor) {
1.34      eric     1213:        Finger * finger = (Finger *) HTRequest_context(text->request);
                   1214:        Robot * mr = finger->robot;
1.75      frystyk  1215: 
1.59      frystyk  1216:        if (mr->flags & MR_IMG) {
1.60      frystyk  1217:            HTAnchor * dest = HTAnchor_followMainLink((HTAnchor *) anchor);
                   1218:            HTParentAnchor * dest_parent = HTAnchor_parent(dest);
                   1219:            char * uri = HTAnchor_address((HTAnchor *) dest_parent);
                   1220:            HyperDoc * hd = HTAnchor_document(dest_parent);
                   1221:            HTParentAnchor * referer = HTRequest_anchor(text->request);
1.59      frystyk  1222:            BOOL match = YES;
                   1223: 
1.72      frystyk  1224:            if (!uri) return;
1.59      frystyk  1225:            if (hd) {
1.82      frystyk  1226:                if (SHOW_QUIET(mr)) HTPrint("............ Already checked\n");
1.59      frystyk  1227:                hd->hits++;
1.68      frystyk  1228: #ifdef HT_MYSQL
                   1229:                if (mr->sqllog) {
                   1230:                    char * ref_addr = HTAnchor_address((HTAnchor *) referer);
                   1231:                    if (ref_addr) {
                   1232:                        HTSQLLog_addLinkRelationship(mr->sqllog,
                   1233:                                                     ref_addr, uri,
                   1234:                                                     "image", alt);
                   1235:                        HT_FREE(ref_addr);
                   1236:                    }
                   1237:                }
                   1238: #endif
1.11      frystyk  1239:                HT_FREE(uri);
1.59      frystyk  1240:                return;
1.2       frystyk  1241:            }
1.59      frystyk  1242: 
                   1243:            /* Check for prefix match */
                   1244:            if (mr->img_prefix) match = HTStrMatch(mr->img_prefix, uri) ? YES : NO;
                   1245: 
1.79      br334    1246: #ifdef HT_POSIX_REGEX
                   1247:        /*
                   1248:        **  Check for any regular expression. The include may override
                   1249:        **  the prefix matching
                   1250:        */
                   1251:        if (mr->include) {
                   1252:            match = regexec(mr->include, uri, 0, NULL, 0) ? NO : YES;
                   1253:        }
                   1254:        if (match && mr->exc_robot) {
                   1255:            match = regexec(mr->exc_robot, uri, 0, NULL, 0) ? YES : NO;
                   1256:        }
                   1257:        if (match && mr->exclude) {
                   1258:            match = regexec(mr->exclude, uri, 0, NULL, 0) ? YES : NO;
                   1259:        }
                   1260: #endif
1.59      frystyk  1261:            /* Test whether we already have a hyperdoc for this document */
                   1262:            if (match && dest) {
1.60      frystyk  1263:                Finger * newfinger = Finger_new(mr, dest_parent,
1.59      frystyk  1264:                                                mr->flags & MR_SAVE ?
                   1265:                                                METHOD_GET : METHOD_HEAD);
                   1266:                HTRequest * newreq = newfinger->request;
1.60      frystyk  1267:                HyperDoc_new(mr, dest_parent, 1);
                   1268:                HTRequest_setParent(newreq, referer);
                   1269: 
                   1270:                /* Check whether we should report missing ALT tags */
                   1271:                if (mr->noalttag && (alt==NULL || *alt=='\0')) {
                   1272:                    if (referer) {
                   1273:                        char * ref_addr = HTAnchor_address((HTAnchor *) referer);
                   1274:                        if (ref_addr) HTLog_addText(mr->noalttag, "%s --> %s\n", ref_addr, uri);
                   1275:                        HT_FREE(ref_addr);
                   1276:                    }
                   1277:                }
                   1278:                
1.82      frystyk  1279:                if (SHOW_QUIET(mr)) HTPrint("Robot....... Checking Image `%s\'\n", uri);
1.59      frystyk  1280:                if (HTLoadAnchor((HTAnchor *) dest, newreq) != YES) {
1.82      frystyk  1281:                    if (SHOW_QUIET(mr)) HTPrint("Robot....... Image not tested!\n");
1.59      frystyk  1282:                    Finger_delete(newfinger);
                   1283:                }
                   1284:            } else {
1.82      frystyk  1285:                if (SHOW_QUIET(mr)) HTPrint("............ does not fulfill constraints\n");
1.68      frystyk  1286: #ifdef HT_MYSQL
                   1287:                if (mr->reject || mr->sqllog) {
                   1288: #else  
1.60      frystyk  1289:                if (mr->reject) {
1.68      frystyk  1290: #endif
1.60      frystyk  1291:                    if (referer) {
                   1292:                        char * ref_addr = HTAnchor_address((HTAnchor *) referer);
1.68      frystyk  1293:                        if (mr->reject && ref_addr)
                   1294:                            HTLog_addText(mr->reject, "%s --> %s\n", ref_addr, uri);
                   1295: #ifdef HT_MYSQL
                   1296:                        if (mr->sqllog && mr->sqlexternals && ref_addr)
                   1297:                            HTSQLLog_addLinkRelationship(mr->sqllog,
                   1298:                                                         ref_addr, uri,
                   1299:                                                         "image", alt);
                   1300: #endif
                   1301: 
1.60      frystyk  1302:                        HT_FREE(ref_addr);
                   1303:                    }
                   1304:                }
1.1       frystyk  1305:            }
1.59      frystyk  1306:            HT_FREE(uri);
1.72      frystyk  1307:        }
                   1308:     }
                   1309: }
                   1310: 
1.80      frystyk  1311: PRIVATE void RHText_foundLink (HText * text,
                   1312:                               int element_number, int attribute_number,
                   1313:                               HTChildAnchor * anchor,
                   1314:                               const BOOL * present, const char ** value)
1.72      frystyk  1315: {
                   1316:     if (text && anchor) {
                   1317:        Finger * finger = (Finger *) HTRequest_context(text->request);
                   1318:        Robot * mr = finger->robot;
                   1319:        if (SHOW_QUIET(mr))
1.82      frystyk  1320:            HTPrint("Robot....... Received element %d, attribute %d with anchor %p\n",
1.80      frystyk  1321:                    element_number, attribute_number, anchor);
                   1322:        if ((element_number==HTML_IMG && attribute_number==HTML_IMG_SRC) || 
                   1323:            (element_number==HTML_BODY && attribute_number==HTML_BODY_BACKGROUND))
                   1324:            RHText_foundImage(text, anchor, NULL, NULL, NO);
                   1325:        else
                   1326:            RHText_foundAnchor(text, anchor);
1.72      frystyk  1327:     }
                   1328: }
                   1329: 
1.80      frystyk  1330: PUBLIC char * get_robots_txt(char * uri)
1.48      frystyk  1331: {
1.75      frystyk  1332:   char *str = NULL;
                   1333:   HTChunk * chunk;
                   1334:   HTParentAnchor *anchor = HTAnchor_parent(HTAnchor_findAddress(uri));
                   1335:   HTRequest *request = HTRequest_new();
                   1336:   HTRequest_setOutputFormat(request, WWW_SOURCE);
                   1337:   HTRequest_setPreemptive(request, YES);
                   1338:   HTRequest_setMethod(request, METHOD_GET);
                   1339:   chunk = HTLoadAnchorToChunk ((HTAnchor *)anchor, request);
                   1340:   str = HTChunk_toCString(chunk);
                   1341:   HTRequest_delete(request);
                   1342:   return str;
1.48      frystyk  1343: }
                   1344: 

Webmaster