Annotation of libwww/Library/src/HTSQLLog.c, revision 2.1
2.1 ! frystyk 1: /* HTSQL.c
! 2: ** SQL LOGGING MODULE
! 3: **
! 4: ** (c) COPYRIGHT MIT 1995.
! 5: ** Please first read the full copyright statement in the file COPYRIGH.
! 6: ** @(#) $Id: HTLog.c,v 2.21 1998/02/01 19:04:10 frystyk Exp $
! 7: **
! 8: ** This module contains a simple SQL based logging mechanism for requests
! 9: ** and anything else you want to log
! 10: **
! 11: ** History:
! 12: ** 23 Apr 98 Henrik Frystyk, frystyk@w3.org
! 13: */
! 14:
! 15: /* Library include files */
! 16: #include "WWWLib.h"
! 17: #include "HTSQLLog.h" /* Implemented here */
! 18:
! 19: #include <mysql.h>
! 20:
! 21: struct _HTSQLLog {
! 22: MYSQL server;
! 23: MYSQL * psvr;
! 24: const char * host;
! 25: const char * user;
! 26: const char * password; /* @@@ Should be scambled! @@@ */
! 27: char * relative; /* Make URIs relative to */
! 28: int accesses;
! 29: };
! 30:
! 31: #define DEFAULT_SQL_URIS_TABLE "uris"
! 32: #define DEFAULT_SQL_REQUESTS_TABLE "requests"
! 33: #define DEFAULT_SQL_RESOURCES_TABLE "resources"
! 34: #define DEFAULT_SQL_LINKS_TABLE "links"
! 35:
! 36: #define DEFAULT_SQL_KEY_TYPE "int unsigned not null "
! 37: #define MAX_URI_LENGTH "255"
! 38:
! 39: #define SHOWLOG 1
! 40: #undef SQL_DEBUG
! 41:
! 42: /* ------------------------------------------------------------------------- */
! 43:
! 44: PRIVATE int sql_datetimestr (char ** ptr, time_t t)
! 45: {
! 46: int length = -1;
! 47: if (t > 0 && *ptr) {
! 48: #if defined(HT_REENTRANT) || defined(SOLARIS)
! 49: struct tm gmt;
! 50: struct * pgmt = gmtime_r(&t, &gmt);
! 51: #else
! 52: struct tm *pgmt = gmtime(&t);
! 53: #endif /* SOLARIS || HT_REENTRANT */
! 54:
! 55: #ifdef HAVE_STRFTIME
! 56: length = strftime(*ptr, 40, "\'%Y-%m-%d %H:%M:%S\'", pgmt);
! 57: #else
! 58: length = sprintf(*ptr, "\'%04d-%02d-%02d %02d:%02d:%02d\'",
! 59: pgmt->tm_year + 1900,
! 60: pgmt->tm_mon + 1,
! 61: pgmt->tm_wday + 1,
! 62: pgmt->tm_hour,
! 63: pgmt->tm_min,
! 64: pgmt->tm_sec);
! 65: #endif /* HAVE_STRFTIME */
! 66:
! 67: /* Remove the trailing zero */
! 68: *ptr = *ptr + strlen(*ptr);
! 69: **ptr++ = ' ';
! 70: }
! 71: return length;
! 72: }
! 73:
! 74: PRIVATE char * sql_printf (char * buf, int length, char * fmt, ...)
! 75: {
! 76: va_list pArgs;
! 77: char * p=fmt;
! 78: char * q=buf;
! 79: char * cpar;
! 80: unsigned upar;
! 81: long lpar;
! 82: time_t tpar;
! 83: va_start(pArgs, fmt);
! 84: while (*p && length>0) {
! 85: if (*p == '%') {
! 86: switch (*++p) {
! 87: case 's':
! 88: if ((cpar = va_arg(pArgs, char *)) != NULL) {
! 89: char * cp = cpar;
! 90: while ((*q++ = *cp++) && length-->0); q--;
! 91: } else {
! 92: *q++='n'; *q++='u'; *q++='l'; *q++='l';
! 93: length -= 4;
! 94: }
! 95: break;
! 96: case 'S':
! 97: if ((cpar = va_arg(pArgs, char *)) != NULL) {
! 98: char * cp = cpar;
! 99: *q++='\'';
! 100: mysql_escape_string(q, cp, strlen(cp));
! 101: while (*q) q++, length--;
! 102: *q++='\'';
! 103: } else {
! 104: *q++='n'; *q++='u'; *q++='l'; *q++='l';
! 105: length -= 4;
! 106: }
! 107: break;
! 108: case 'T':
! 109: if ((tpar = va_arg(pArgs, time_t)) > 0) {
! 110: length -= sql_datetimestr(&q, tpar);
! 111: } else {
! 112: *q++='n'; *q++='u'; *q++='l'; *q++='l';
! 113: length -= 4;
! 114: }
! 115: break;
! 116: case 'u':
! 117: if ((upar = va_arg(pArgs, unsigned int)) >= 0) {
! 118: char num[32];
! 119: char * nptr = num;
! 120: int i;
! 121: do {
! 122: i = upar % 10;
! 123: *nptr++ = i+'0';
! 124: upar /= 10;
! 125: } while (upar > 0);
! 126: while (nptr > num && length>0) *q++=*--nptr, length--;
! 127: } else {
! 128: *q++='0';
! 129: length--;
! 130: }
! 131: break;
! 132: case 'l':
! 133: if ((lpar = va_arg(pArgs, unsigned long)) >= 0) {
! 134: char num[32];
! 135: char * nptr = num;
! 136: int i;
! 137: do {
! 138: i = lpar % 10;
! 139: *nptr++ = i+'0';
! 140: lpar /= 10;
! 141: } while (lpar > 0);
! 142: while (nptr > num && length>0) *q++=*--nptr, length--;
! 143: } else {
! 144: *q++='0';
! 145: length--;
! 146: }
! 147: break;
! 148: default:
! 149: *q++=*p++;
! 150: length--;
! 151: }
! 152: p++;
! 153: } else {
! 154: *q++=*p++;
! 155: length--;
! 156: }
! 157: }
! 158: *q = '\0';
! 159: va_end(pArgs);
! 160: return buf;
! 161: }
! 162:
! 163: PRIVATE int find_uri(HTSQLLog * me, const char * uri)
! 164: {
! 165: int index = -1;
! 166: if (me && me->psvr && uri) {
! 167: char buf[1024];
! 168: char * query = NULL;
! 169: MYSQL_RES * result = NULL;
! 170:
! 171: /* Make the query */
! 172: query = sql_printf(buf, 1024, "select * from %s where uri=%S",
! 173: DEFAULT_SQL_URIS_TABLE, uri);
! 174: #if SQL_DEBUG
! 175: fprintf(stderr, "%s\n", query);
! 176: #endif
! 177: if (!mysql_query(me->psvr, query) &&
! 178: (result = mysql_store_result(me->psvr)) != NULL) {
! 179: MYSQL_ROW row;
! 180: if ((row = mysql_fetch_row(result)) && row[0])
! 181: index = atoi(row[0]);
! 182: mysql_free_result(result);
! 183: }
! 184: }
! 185: return index;
! 186: }
! 187:
! 188: PRIVATE int add_uri (HTSQLLog * me, const char * uri)
! 189: {
! 190: if (me && me->psvr && uri) {
! 191: int index = -1;
! 192: char * rel = me->relative ? HTRelative(uri, me->relative) : NULL;
! 193:
! 194: /* If we can't find the URI then add it */
! 195: if ((index = find_uri(me, rel ? rel : uri)) < 0) {
! 196: char buf[1024];
! 197: char * query = NULL;
! 198: query = sql_printf(buf, 1024, "insert into %s (uri) values (%S)",
! 199: DEFAULT_SQL_URIS_TABLE, rel ? rel : uri);
! 200: #ifdef SQL_DEBUG
! 201: fprintf(stderr, "%s\n", query);
! 202: #endif
! 203: if (mysql_query(me->psvr, query) < 0) {
! 204: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 205: mysql_error(me->psvr), query,mysql_errno(me->psvr));
! 206: HT_FREE(rel);
! 207: return -1;
! 208: }
! 209: index = mysql_insert_id(me->psvr);
! 210: }
! 211: HT_FREE(rel);
! 212: return index;
! 213: }
! 214: return -1;
! 215: }
! 216:
! 217: PRIVATE BOOL add_linktype (HTSQLLog * me, int srcidx, int dstidx,
! 218: const char * type, const char * comment)
! 219: {
! 220: if (me && me->psvr && srcidx>=0 && dstidx>=0 && type) {
! 221: char buf[1024];
! 222: char * query = NULL;
! 223: query = sql_printf(buf, 1024, "insert into %s values (%u,%u,%S,%S)",
! 224: DEFAULT_SQL_LINKS_TABLE,
! 225: srcidx, dstidx, type, comment);
! 226: #ifdef SQL_DEBUG
! 227: fprintf(stderr, "%s\n", query);
! 228: #endif
! 229: if (mysql_query(me->psvr, query) < 0 && mysql_errno(me->psvr) != 1062) {
! 230: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 231: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 232: return NO;
! 233: }
! 234: return YES;
! 235: }
! 236: return NO;
! 237: }
! 238:
! 239: PRIVATE BOOL clear_table (HTSQLLog * me, const char * table)
! 240: {
! 241: BOOL status = NO;
! 242: char * query = NULL;
! 243: if (me && me->psvr && table) {
! 244: if (SHOWLOG) HTTrace("SQLLog...... Clearing table `%s\'\n", table);
! 245: query = StrAllocMCopy(&query, "delete from ", table, NULL);
! 246: #ifdef SQL_DEBUG
! 247: fprintf(stderr, "%s\n", query);
! 248: #endif
! 249: if (mysql_query(me->psvr, query) < 0) {
! 250: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 251: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 252: } else
! 253: status = YES;
! 254: }
! 255: HT_FREE(query);
! 256: return status;
! 257: }
! 258:
! 259: PRIVATE BOOL drop_table (HTSQLLog * me, const char * table)
! 260: {
! 261: BOOL status = NO;
! 262: char * query = NULL;
! 263: if (me && me->psvr && table) {
! 264: if (SHOWLOG) HTTrace("SQLLog...... Clearing table `%s\'\n", table);
! 265: query = StrAllocMCopy(&query, "drop table ", table, NULL);
! 266: #ifdef SQL_DEBUG
! 267: fprintf(stderr, "%s\n", query);
! 268: #endif
! 269: if (mysql_query(me->psvr, query) < 0) {
! 270: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 271: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 272: } else
! 273: status = YES;
! 274: }
! 275: HT_FREE(query);
! 276: return status;
! 277: }
! 278:
! 279: PRIVATE BOOL createTables (HTSQLLog * me, HTSQLLogFlags flags)
! 280: {
! 281: if (me && me->psvr) {
! 282: char * query = NULL;
! 283: if (SHOWLOG) HTTrace("SQLLog...... Creating log tables\n");
! 284:
! 285: /* If we have to delete it first */
! 286: if (flags & HTSQLLOG_DROP_URIS_TABLE)
! 287: drop_table(me, DEFAULT_SQL_URIS_TABLE);
! 288:
! 289: /* Create URI table (which is the index) */
! 290: query = StrAllocMCopy(&query, "create table ", DEFAULT_SQL_URIS_TABLE, " ( ",
! 291: "id ", DEFAULT_SQL_KEY_TYPE, " auto_increment, ",
! 292: "uri varchar(", MAX_URI_LENGTH, ") binary not null, ",
! 293: "primary key (id), "
! 294: "unique (uri), ",
! 295: "index uri_idx (uri(32))",
! 296: ")", NULL);
! 297: #ifdef SQL_DEBUG
! 298: fprintf(stderr, "%s\n", query);
! 299: #endif
! 300: if (mysql_query(me->psvr, query) < 0) {
! 301: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 302: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 303: }
! 304:
! 305: /* If we have to clear it out */
! 306: if (flags & HTSQLLOG_CLEAR_URIS_TABLE)
! 307: clear_table(me, DEFAULT_SQL_URIS_TABLE);
! 308:
! 309: /* If we have to delete it first */
! 310: if (flags & HTSQLLOG_DROP_REQUESTS_TABLE)
! 311: drop_table(me, DEFAULT_SQL_REQUESTS_TABLE);
! 312:
! 313: /* Create Request table */
! 314: query = StrAllocMCopy(&query, "create table ", DEFAULT_SQL_REQUESTS_TABLE, " ( ",
! 315: "uri ", DEFAULT_SQL_KEY_TYPE, " primary key, ",
! 316: "method char(16) not null, ",
! 317: "status int unsigned not null, ",
! 318: "request_time datetime, ",
! 319: "response_time datetime ",
! 320: ")", NULL);
! 321: #ifdef SQL_DEBUG
! 322: fprintf(stderr, "%s\n", query);
! 323: #endif
! 324: if (mysql_query(me->psvr, query) < 0) {
! 325: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 326: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 327: }
! 328:
! 329: /* If we have to clear it out */
! 330: if (flags & HTSQLLOG_CLEAR_REQUESTS_TABLE)
! 331: clear_table(me, DEFAULT_SQL_REQUESTS_TABLE);
! 332:
! 333: /* If we have to delete it first */
! 334: if (flags & HTSQLLOG_DROP_RESOURCES_TABLE)
! 335: drop_table(me, DEFAULT_SQL_RESOURCES_TABLE);
! 336:
! 337: /* Create Resource table */
! 338: query = StrAllocMCopy(&query, "create table ", DEFAULT_SQL_RESOURCES_TABLE," ( ",
! 339: "uri ", DEFAULT_SQL_KEY_TYPE, " primary key, ",
! 340: "length bigint unsigned not null, ",
! 341: "last_modified datetime, ",
! 342: "expires datetime, ",
! 343: "content_type char(32), ",
! 344: "charset char(32), ",
! 345: "content_encoding char(32), ",
! 346: "content_language char(32), ",
! 347: "title char(128) ",
! 348: ")", NULL);
! 349: #ifdef SQL_DEBUG
! 350: fprintf(stderr, "%s\n", query);
! 351: #endif
! 352: if (mysql_query(me->psvr, query) < 0) {
! 353: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 354: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 355: }
! 356:
! 357: /* If we have to clear it out */
! 358: if (flags & HTSQLLOG_CLEAR_RESOURCES_TABLE)
! 359: clear_table(me, DEFAULT_SQL_RESOURCES_TABLE);
! 360:
! 361: /* If we have to delete it first */
! 362: if (flags & HTSQLLOG_DROP_LINKS_TABLE)
! 363: drop_table(me, DEFAULT_SQL_LINKS_TABLE);
! 364:
! 365: /* Create Link Relations table */
! 366: query = StrAllocMCopy(&query, "create table ", DEFAULT_SQL_LINKS_TABLE, " ( ",
! 367: "source ", DEFAULT_SQL_KEY_TYPE, ", ",
! 368: "destination ", DEFAULT_SQL_KEY_TYPE, ", ",
! 369: "link_type char(32) not null, ",
! 370: "comment char(128), ",
! 371: "unique (source, destination, link_type) ",
! 372: ")", NULL);
! 373: #ifdef SQL_DEBUG
! 374: fprintf(stderr, "%s\n", query);
! 375: #endif
! 376: if (mysql_query(me->psvr, query) < 0) {
! 377: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 378: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 379: }
! 380:
! 381: /* If we have to clear it out */
! 382: if (flags & HTSQLLOG_CLEAR_LINKS_TABLE)
! 383: clear_table(me, DEFAULT_SQL_LINKS_TABLE);
! 384:
! 385: HT_FREE(query);
! 386: return YES;
! 387: }
! 388: return NO;
! 389: }
! 390:
! 391: /* Open a connection
! 392: ** -----------------
! 393: ** Returns YES if OK, NO on error
! 394: */
! 395: PUBLIC HTSQLLog * HTSQLLog_connect (const char * host,
! 396: const char * user, const char * pw)
! 397: {
! 398: HTSQLLog * me;
! 399: if (!host || !user || !pw) {
! 400: if (SHOWLOG) HTTrace("SQLLog...... Missing SQLLog host, user, or password\n");
! 401: return NULL;
! 402: }
! 403: if ((me = (HTSQLLog *) HT_CALLOC(1, sizeof(HTSQLLog))) == NULL)
! 404: HT_OUTOFMEM("HTSQLLog_open");
! 405:
! 406: if (SHOWLOG) HTTrace("SQLLog...... Open a link to server `%s\'\n", host);
! 407: if ((me->psvr = mysql_connect(&(me->server), host, user, pw)) == NULL) {
! 408: if (SHOWLOG)
! 409: HTTrace("SQLLog...... `%s\' errno %d\n",
! 410: mysql_error(&me->server), mysql_errno(&me->server));
! 411: HT_FREE(me);
! 412: return NULL;
! 413: }
! 414: me->host = host;
! 415: me->user = user;
! 416: me->password = pw; /* @@@ scramble!!! @@@ */
! 417: return me;
! 418: }
! 419:
! 420:
! 421: /* Close connection
! 422: ** ----------------
! 423: ** Returns YES if OK, NO on error
! 424: */
! 425: PUBLIC BOOL HTSQLLog_close (HTSQLLog * me)
! 426: {
! 427: if (me && me->psvr) {
! 428: if (SHOWLOG) HTTrace("SQLLog...... Closing link to host `%s\'\n", me->host);
! 429: mysql_close(me->psvr);
! 430: HT_FREE(me->relative);
! 431: HT_FREE(me);
! 432: return YES;
! 433: }
! 434: return NO;
! 435: }
! 436:
! 437: PUBLIC BOOL HTSQLLog_clearTables (HTSQLLog * me)
! 438: {
! 439: if (me && me->psvr) {
! 440:
! 441: /* ... */
! 442:
! 443: return YES;
! 444: }
! 445: return NO;
! 446: }
! 447:
! 448: PUBLIC BOOL HTSQLLog_makeRelativeTo (HTSQLLog * me, const char * relative)
! 449: {
! 450: if (me) {
! 451: StrAllocCopy(me->relative, relative);
! 452: return YES;
! 453: }
! 454: return NO;
! 455: }
! 456:
! 457: PUBLIC BOOL HTSQLLog_openDB (HTSQLLog * me, const char * db,
! 458: HTSQLLogFlags flags)
! 459: {
! 460: BOOL created = NO;
! 461: if (me && me->psvr && db) {
! 462: if (SHOWLOG) HTTrace("SQLLog...... Selecting database `%s\'\n", db);
! 463: if (mysql_select_db(me->psvr, db) < 0) {
! 464: int err = mysql_errno(me->psvr);
! 465: if (SHOWLOG) HTTrace("SQLLog...... `%s\', errno %d\n",
! 466: mysql_error(me->psvr), err);
! 467:
! 468: /* If the database couldn't be found then create a new one */
! 469: if (err == 1049) {
! 470: if (mysql_create_db(me->psvr, db) < 0) {
! 471: if (SHOWLOG) HTTrace("SQLLog...... `%s\', errno %d\n",
! 472: mysql_error(me->psvr), err);
! 473: return NO;
! 474: }
! 475: created = YES;
! 476: } else
! 477: return NO;
! 478: }
! 479:
! 480: if (created) {
! 481: if (mysql_select_db(me->psvr, db) < 0) {
! 482: int err = mysql_errno(me->psvr);
! 483: if (SHOWLOG) HTTrace("SQLLog...... `%s\', errno %d\n",
! 484: mysql_error(me->psvr), err);
! 485: return NO;
! 486: }
! 487: }
! 488:
! 489: /* Create the log tables in the log db */
! 490: createTables(me, flags);
! 491: return YES;
! 492: }
! 493: return NO;
! 494: }
! 495:
! 496: PUBLIC int HTSQLLog_accessCount (HTSQLLog * me)
! 497: {
! 498: return me ? me->accesses : -1;
! 499: }
! 500:
! 501: PUBLIC BOOL HTSQLLog_addURI (HTSQLLog * me, const char * uri)
! 502: {
! 503: return (me && me->psvr && (add_uri(me, uri)>=0));
! 504: }
! 505:
! 506: PUBLIC BOOL HTSQLLog_addLinkRelationship (HTSQLLog * me,
! 507: const char * src_uri,
! 508: const char * dst_uri,
! 509: const char * link_type,
! 510: const char * comment)
! 511: {
! 512: if (src_uri && dst_uri) {
! 513: int srcidx = add_uri(me, src_uri);
! 514: int dstidx = add_uri(me, dst_uri);
! 515: return add_linktype(me, srcidx, dstidx, link_type, comment);
! 516: }
! 517: return NO;
! 518: }
! 519:
! 520: PUBLIC BOOL HTSQLLog_addEntry (HTSQLLog * me, HTRequest * request, int status)
! 521: {
! 522: if (me && me->psvr) {
! 523: HTParentAnchor * anchor = HTRequest_anchor(request);
! 524: HTParentAnchor * parent_anchor = HTRequest_parent(request);
! 525: char * uri = HTAnchor_address((HTAnchor *) anchor);
! 526: int index = 0;
! 527: char buf[512];
! 528: char * query = NULL;
! 529:
! 530: /* Insert into the URI table */
! 531: if ((index = add_uri(me, uri)) < 0) return NO;
! 532:
! 533: /* Insert into the request table */
! 534: query = sql_printf(buf, 512, "replace into %s values (%u,%S,%u,%T,%T)",
! 535: DEFAULT_SQL_REQUESTS_TABLE,
! 536: index,
! 537: HTMethod_name(HTRequest_method(request)),
! 538: abs(status),
! 539: HTRequest_date(request),
! 540: HTAnchor_date(anchor));
! 541: #ifdef SQL_DEBUG
! 542: fprintf(stderr, "%s\n", query);
! 543: #endif
! 544: if (mysql_query(me->psvr, query) < 0) {
! 545: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 546: mysql_error(me->psvr), query, mysql_errno(me->psvr));
! 547: return NO;
! 548: }
! 549:
! 550: /* Insert into the resource table */
! 551: {
! 552: HTList * encodings = HTAnchor_encoding(anchor);
! 553: HTList * languages = HTAnchor_language(anchor);
! 554: HTFormat format = HTAnchor_format(anchor);
! 555: HTCharset charset = HTAnchor_charset(anchor);
! 556: HTEncoding encoding = encodings ? HTList_firstObject(encodings) : NULL;
! 557: HTLanguage language = languages ? HTList_firstObject(languages) : NULL;
! 558: query = sql_printf(buf, 512, "replace into %s values (%u,%l,%T,%T,%S,%S,%S,%S,%S)",
! 559: DEFAULT_SQL_RESOURCES_TABLE,
! 560: index,
! 561: HTAnchor_length(anchor),
! 562: HTAnchor_lastModified(anchor),
! 563: HTAnchor_expires(anchor),
! 564: format != WWW_UNKNOWN ? HTAtom_name(format) : NULL,
! 565: charset ? HTAtom_name(charset) : NULL,
! 566: encoding ? HTAtom_name(encoding) : NULL,
! 567: language ? HTAtom_name(language) : NULL,
! 568: HTAnchor_title(anchor));
! 569: #ifdef SQL_DEBUG
! 570: fprintf(stderr, "%s\n", query);
! 571: #endif
! 572: if (mysql_query(me->psvr, query) < 0) {
! 573: if (SHOWLOG) HTTrace("SQLLog...... `%s\' on query `%s\' with errno %d\n",
! 574: mysql_error(me->psvr), query,mysql_errno(me->psvr));
! 575: return NO;
! 576: }
! 577: }
! 578:
! 579: /* Insert into the relationship table */
! 580: if (parent_anchor) {
! 581: char * parent = HTAnchor_address((HTAnchor *) parent_anchor);
! 582: if (uri && parent && *parent) {
! 583: int srcidx = add_uri(me, parent);
! 584: add_linktype(me, srcidx, index, "referer", NULL);
! 585: }
! 586: HT_FREE(parent);
! 587: }
! 588:
! 589: /* Count one more access */
! 590: me->accesses++;
! 591:
! 592: HT_FREE(uri);
! 593: return YES;
! 594: }
! 595: return NO;
! 596: }
! 597:
! 598:
Webmaster