/* @(#)remote.c 1.6 95/09/16 */ /* * Copyright (c) 1994, 1995 by Wayne C. Gramlich. All rights reserved. * * Permission to use, copy, modify, distribute, and sell this software * for any purpose is hereby granted without fee provided that the above * copyright notice and this permission are retained. The author makes * no representations about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. */ /* LINTLIBRARY */ #include "assert.h" #include "config_extern.h" #include "error_extern.h" #include "html_extern.h" #include "local_extern.h" #include "link_extern.h" #include "memory_extern.h" #include "remote_extern.h" #include "str_extern.h" #include "text_extern.h" #include "vector_extern.h" #include "url_extern.h" struct remote_struct { int is_dummy; /* 1=>dummy remote object; 0=>the real thing. */ Links links; /* List of hyper text links in document */ unsigned timestamp; /* Timestamp of when document was accessed */ Str title; /* Document title */ Url url; /* Url for remote document */ }; static int remote_is_dummy(Remote); /* * remote_create(url) * This routine will create and return a {Remote} object * that contains {url} and all other fields zeroed out. */ static Remote remote_create( Url url) { Remote remote; remote = (Remote)memory_allocate_zeroed(sizeof *remote); remote->is_dummy = 0; remote->url = url; remote->links = links_create(); return remote; } /* * remote_create_dummy() * This routine will create a dummy {Remote} object and return * it. It is useful to implementing the {post_solicit} program. */ Remote remote_create_dummy(void) { Remote remote; Url url; url = url_parse((Str)"http://_/_.html"); remote = remote_create(url); remote->is_dummy = 1; return remote; } /* * remote_is_dummy(remote) * This routine will return 1 if {remote} is a dummy remote object * (created by {remote_create_dummy}(); otherwise, 0 is returned. */ static int remote_is_dummy( Remote remote) { return remote->is_dummy; } /* * remote_links(remote) * This routine will return the links associated with {remote}. */ Links remote_links( Remote remote) { return remote->links; } /* * remote_restore(in_file, errors) * This routine will read a {Remote} object from {in_file} that was * written by {remote_save()} and return it. */ static Remote remote_restore( FILE *in_file, Errors errors) { Remote remote; Url url; remote = (Remote)0; if (getc(in_file) != 'R') { goto error; } if (getc(in_file) != ' ') { goto error; } url = url_restore(in_file); remote = remote_create(url); if (getc(in_file) != ' ') { goto error; } (void)fscanf(in_file, "%u", &remote->timestamp); if (getc(in_file) != ' ') { goto error; } remote->title = str_restore(in_file); if (getc(in_file) != '\n') { goto error; } remote->links = links_restore(remote, in_file, errors); return remote; error: errors_append(errors, (Str)"Trouble restoring remote object."); return remote; } /* * remote_save(remote, out_file) * This routine will write {remote} to {out_file} in such a way that it * can be reread via remote_restore(). */ static void remote_save( Remote remote, FILE *out_file) { (void)fprintf(out_file, "R "); url_save(remote->url, out_file); (void)fprintf(out_file, " %u ", remote->timestamp); str_save(remote->title, out_file); (void)fprintf(out_file, "\n"); links_save(remote->links, out_file); } /* * remote_scan(remote_url_str, config, errors) * This routine will read in the document named by {remote_url_str}, * scan it for hyptertext links to documents residing the machine * named in {config}. If any errors occur, {errors} is updated to * explain what went wrong. */ Remote remote_scan( Str remote_url_str, Config config, Errors errors) { Link link; Links links; Remote remote; Html remote_html; Url remote_url; Tag tag; Tags tags; /* Slurp in the reference document: */ remote_url = url_parse(remote_url_str); remote = remote_create(remote_url); remote_html = html_read(remote_url, errors); if (errors_size(errors) != 0) { return remote; } /* Search for all references to documents on current machine: */ tags = html_tags(remote_html); remote->title = (Str)""; TAG_END_SEARCH(tag, tags, (Str)"TITLE") { remote->title = text_str_copy(tag_preceeding_text(tag)); break; } links = links_create(); remote->links = links; TAG_START_SEARCH(tag, tags, (Str)"A") { attributes_scan(tag_attributes(tag), remote, config); } /* If no reference documents found, return error message: */ if (links_size(links) == 0) { Str message; message = str_printf("No hypertext links to documents on `%s' found!", config_host_name(config)); errors_append(errors, message); return remote; } LINKS_LOOP(link, links) { local_update(link_href(link), link_remote(link), config, errors); } return remote; } /* * remote_title(remote) * This routine will return the title associated with {remote}. */ Str remote_title( Remote remote) { return remote->title; } /* * remote_url(remote) * This routine will return the URL associated with {remote}. */ Url remote_url( Remote remote) { return remote->url; } /* * remotes_create() * This routine will create an return a {Remotes} object. */ Remotes remotes_create(void) { return (Remotes)vector_create(); } /* * remotes_append(remotes, remote) * This routine will append {remote} to {remotes}. */ void remotes_append( Remotes remotes, Remote remote) { vector_append((Vector)remotes, (Pointer)remote); } /* * remotes_inline_search(remotes, html) * This routine will use the URL of each {Remote} object in {remotes} * search for inline patterns in {html}. The list of pattern matches * is returned. */ Matches remotes_inline_search( Remotes remotes, Html html) { Matches matches; Remote remote; matches = matches_create(); REMOTES_LOOP(remote, remotes) { Link link; Links links; links = remote->links; LINKS_LOOP(link, links) { Match match; Str pattern; Url url; url = link_href(link); pattern = url_anchor(url); if (!str_is_empty(pattern)) { match = html_search(html, pattern, remote); if (match != (Match)0) { matches_append(matches, match); } } } } matches_sort(matches); return matches; } /* * remotes_merge(remotes, remote_new) * This routine will merge {remote_new} into {remotes} saving * any appropriate information from previos times. The resulting * merged database is returned. */ void remotes_merge( Remotes remotes, Remote remote_new) { Remote remote; REMOTES_LOOP(remote, remotes) { if (url_document_equal(remote->url, remote_new->url)) { links_votes_merge(remote->links, remote_new->links); remote->links = remote_new->links; remote->timestamp = remote_new->timestamp; return; } } if (!remote_is_dummy(remote_new)) { remotes_append(remotes, remote_new); } } /* * remotes_restore(db_file_name, errors) * This routine will read all of the {Remote} objects contained in * the file named {db_file_name} and return them. */ Remotes remotes_restore( Str db_file_name, Errors errors) { FILE *db_file; unsigned index; Remote remote; Remotes remotes; unsigned size; remotes = remotes_create(); db_file = fopen((char *)db_file_name, "r"); if (db_file == (FILE *)0) { return remotes; } (void)fscanf(db_file, "%u\n", &size); for (index = 0; index < size; index++) { remote = remote_restore(db_file, errors); remotes_append(remotes, remote); } return remotes; } /* * remotes_save(remotes, db_file_name, errors) * This routine will write {remotes} to the file named {db_file_name}. */ void remotes_save( Remotes remotes, Str db_file_name, Errors errors) { FILE *db_file; Remote remote; db_file = fopen((char *)db_file_name, "w"); if (db_file == (FILE *)0) { Str message; message = str_printf("Could not open file `%s'!", db_file_name); errors_append(errors, message); return; } (void)fprintf(db_file, "%u\n", remotes_size(remotes)); REMOTES_LOOP(remote, remotes) { remote_save(remote, db_file); } (void)fclose(db_file); } /* * remotes_size(remotes) * This routine will return the number of {Remote} objects in {remotes}. */ unsigned remotes_size( Remotes remotes) { unsigned size; size = vector_size((Vector)remotes); return size; } /* * remote_write(remote, annote_file, config) * This routine will write {remote} to {annote_file} as some HTML. */ void remote_write( Remote remote, FILE *annote_file, Config config) { (void)fprintf(annote_file, "