wwwoffle.c
上传用户:seven77cht
上传日期:2007-01-04
资源大小:486k
文件大小:28k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/wwwoffle.c 2.29 1999/10/15 09:26:54 amb Exp $
  3.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.5b.
  4.   A user level program to interact with the server.
  5.   ******************/ /******************
  6.   Written by Andrew M. Bishop
  7.   This file Copyright 1996,97,98,99 Andrew M. Bishop
  8.   It may be distributed under the GNU Public License, version 2, or
  9.   any higher version.  See section COPYING of the GNU Public license
  10.   for conditions under which this file may be redistributed.
  11.   ***************************************/
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <limits.h>
  16. #include <unistd.h>
  17. #include <sys/stat.h>
  18. #include <fcntl.h>
  19. #include "version.h"
  20. #include "wwwoffle.h"
  21. #include "document.h"
  22. #include "misc.h"
  23. #include "config.h"
  24. #include "sockets.h"
  25. #include "errors.h"
  26. static void usage(int verbose);
  27. /*+ The action to perform. +*/
  28. typedef enum _Action
  29. {
  30.  None,                          /*+ Undecided. +*/
  31.  Online,                        /*+ Tell the server that we are online. +*/
  32.  Autodial,                      /*+ Tell the server that we are in autodial mode. +*/
  33.  Offline,                       /*+ Tell the server that we are offline. +*/
  34.  Fetch,                         /*+ Tell the server to fetch the requested pages. +*/
  35.  Config,                        /*+ Tell the server to re-read the configuration file. +*/
  36.  Purge,                         /*+ Tell the server to purge pages. +*/
  37.  Kill,                          /*+ Tell the server to exit. +*/
  38.  Get,                           /*+ Tell the server to GET pages. +*/
  39.  Post,                          /*+ Tell the server to POST a page. +*/
  40.  Put,                           /*+ Tell the server to PUT a page. +*/
  41.  Output,                        /*+ Get a page from the server and output it. +*/
  42.  OutputWithHeader               /*+ Get a page and the headers from the server and output it. +*/
  43. }
  44. Action;
  45. static void add_url_list(char **links);
  46. static void add_url_file(char *url_file);
  47. /*+ The list of URLs or files. +*/
  48. char **url_file_list=NULL;
  49. /*+ The number of URLs or files. +*/
  50. int n_url_file_list=0;
  51. /*++++++++++++++++++++++++++++++++++++++
  52.   The main program.
  53.   ++++++++++++++++++++++++++++++++++++++*/
  54. int main(int argc, char** argv)
  55. {
  56.  int i;
  57.  int recursive_depth=0,recursive_mode=0,force=0;
  58.  int stylesheets=0,images=0,frames=0,scripts=0,objects=0;
  59.  Action action=None;
  60.  char *env=NULL;
  61.  char *host=NULL;
  62.  int port=0;
  63.  /* Parse the command line options */
  64.  ConfigFile=NULL;
  65.  if(argc==1)
  66.     usage(0);
  67.  for(i=1;i<argc;i++)
  68.    {
  69.     if(!strcmp(argv[i],"-h"))
  70.        usage(1);
  71.     if(!strcmp(argv[i],"-o"))
  72.       {
  73.        if(action!=None)
  74.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  75.        action=Output;
  76.        argv[i]=NULL;
  77.        continue;
  78.       }
  79.     if(!strcmp(argv[i],"-O"))
  80.       {
  81.        if(action!=None)
  82.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  83.        action=OutputWithHeader;
  84.        argv[i]=NULL;
  85.        continue;
  86.       }
  87.     if(!strcmp(argv[i],"-post"))
  88.       {
  89.        if(action!=None)
  90.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  91.        action=Post;
  92.        argv[i]=NULL;
  93.        continue;
  94.       }
  95.     if(!strcmp(argv[i],"-put"))
  96.       {
  97.        if(action!=None)
  98.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  99.        action=Put;
  100.        argv[i]=NULL;
  101.        continue;
  102.       }
  103.     if(!strcmp(argv[i],"-F"))
  104.       {
  105.        if(action!=None && action!=Get)
  106.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  107.        action=Get;
  108.        if(force)
  109.          {fprintf(stderr,"wwwoffle: Only one '-F' argument may be given.n"); exit(1);}
  110.        force=1;
  111.        argv[i]=NULL;
  112.        continue;
  113.       }
  114.     if(!strncmp(argv[i],"-g",2))
  115.       {
  116.        if(action!=None && action!=Get)
  117.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  118.        action=Get;
  119.        if(strchr(argv[i]+2,'S'))
  120.          {
  121.           if(stylesheets)
  122.             {fprintf(stderr,"wwwoffle: Only one '-gS' argument may be given.n"); exit(1);}
  123.           stylesheets=1;
  124.          }
  125.        if(strchr(argv[i]+2,'i'))
  126.          {
  127.           if(images)
  128.             {fprintf(stderr,"wwwoffle: Only one '-gi' argument may be given.n"); exit(1);}
  129.           images=1;
  130.          }
  131.        if(strchr(argv[i]+2,'f'))
  132.          {
  133.           if(frames)
  134.             {fprintf(stderr,"wwwoffle: Only one '-gf' argument may be given.n"); exit(1);}
  135.           frames=1;
  136.          }
  137.        if(strchr(argv[i]+2,'s'))
  138.          {
  139.           if(scripts)
  140.             {fprintf(stderr,"wwwoffle: Only one '-gs' argument may be given.n"); exit(1);}
  141.           scripts=1;
  142.          }
  143.        if(strchr(argv[i]+2,'o'))
  144.          {
  145.           if(objects)
  146.             {fprintf(stderr,"wwwoffle: Only one '-go' argument may be given.n"); exit(1);}
  147.           objects=1;
  148.          }
  149.        if(argv[i][2]==0)
  150.           fprintf(stderr,"wwwoffle: The '-g' option does nothing on its own.n");
  151.        argv[i]=NULL;
  152.        continue;
  153.       }
  154.     if(!strcmp(argv[i],"-i"))
  155.       {
  156.        fprintf(stderr,"wwwoffle: The '-i' option is being replaced by '-gi'.n");
  157.        if(action!=None && action!=Get)
  158.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  159.        action=Get;
  160.        if(images)
  161.          {fprintf(stderr,"wwwoffle: Only one '-i' argument may be given.n"); exit(1);}
  162.        images=1;
  163.        argv[i]=NULL;
  164.        continue;
  165.       }
  166.     if(!strcmp(argv[i],"-f"))
  167.       {
  168.        fprintf(stderr,"wwwoffle: The '-f' option is being replaced by '-gf'.n");
  169.        if(action!=None && action!=Get)
  170.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  171.        action=Get;
  172.        if(frames)
  173.          {fprintf(stderr,"wwwoffle: Only one '-f' argument may be given.n"); exit(1);}
  174.        frames=1;
  175.        argv[i]=NULL;
  176.        continue;
  177.       }
  178.     if(!strncmp(argv[i],"-R",2) || !strncmp(argv[i],"-r",2) || !strncmp(argv[i],"-d",2))
  179.       {
  180.        if(action!=None && action!=Get)
  181.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  182.        action=Get;
  183.        if(recursive_depth)
  184.          {fprintf(stderr,"wwwoffle: Only one '-d', '-r' or '-R' argument may be given.n"); exit(1);}
  185.        if(argv[i][1]=='d')
  186.           recursive_mode=1;
  187.        else if(argv[i][1]=='r')
  188.           recursive_mode=2;
  189.        else /* argv[i][1]=='R' */
  190.           recursive_mode=3;
  191.        if(argv[i][2])
  192.           recursive_depth=atoi(&argv[i][2]);
  193.        else
  194.           recursive_depth=1;
  195.        if(recursive_depth<=0)
  196.          {fprintf(stderr,"wwwoffle: The '-%c' argument may only be followed by a positive integer.n",argv[i][1]); exit(1);}
  197.        argv[i]=NULL;
  198.        continue;
  199.       }
  200.     if(!strcmp(argv[i],"-p"))
  201.       {
  202.        char *colon;
  203.        if(++i>=argc)
  204.          {fprintf(stderr,"wwwoffle: The '-p' argument requires a hostname and optionally a port number.n"); exit(1);}
  205.        if(ConfigFile)
  206.          {fprintf(stderr,"wwwoffle: The '-p' and '-c' options cannot be used together.n"); exit(1);}
  207.        if((colon=strchr(argv[i],':')))
  208.          {
  209.           *colon++=0;
  210.           port=atoi(colon);
  211.           if(port<=0 || port>=65536)
  212.             {fprintf(stderr,"wwwoffle: The port number %d '%s' is invalid.n",port,argv[i]); exit(1);}
  213.          }
  214.        host=argv[i];
  215.        argv[i-1]=NULL;
  216.        argv[i]=NULL;
  217.        continue;
  218.       }
  219.     if(!strcmp(argv[i],"-c"))
  220.       {
  221.        if(++i>=argc)
  222.          {fprintf(stderr,"wwwoffle: The '-c' argument requires a configuration file name.n"); exit(1);}
  223.        if(host)
  224.          {fprintf(stderr,"wwwoffle: The '-p' and '-c' options cannot be used together.n"); exit(1);}
  225.        ConfigFile=argv[i];
  226.        argv[i-1]=NULL;
  227.        argv[i]=NULL;
  228.        continue;
  229.       }
  230.     if(!strcmp(argv[i],"-on") || !strcmp(argv[i],"-online"))
  231.       {
  232.        if(action!=None)
  233.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  234.        action=Online;
  235.        argv[i]=NULL;
  236.        continue;
  237.       }
  238.     if(!strcmp(argv[i],"-auto") || !strcmp(argv[i],"-autodial"))
  239.       {
  240.        if(action!=None)
  241.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  242.        action=Autodial;
  243.        argv[i]=NULL;
  244.        continue;
  245.       }
  246.     if(!strcmp(argv[i],"-off") || !strcmp(argv[i],"-offline"))
  247.       {
  248.        if(action!=None)
  249.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  250.        action=Offline;
  251.        argv[i]=NULL;
  252.        continue;
  253.       }
  254.     if(!strcmp(argv[i],"-fetch"))
  255.       {
  256.        if(action!=None)
  257.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  258.        action=Fetch;
  259.        argv[i]=NULL;
  260.        continue;
  261.       }
  262.     if(!strcmp(argv[i],"-config"))
  263.       {
  264.        if(action!=None)
  265.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  266.        action=Config;
  267.        argv[i]=NULL;
  268.        continue;
  269.       }
  270.     if(!strcmp(argv[i],"-purge"))
  271.       {
  272.        if(action!=None)
  273.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  274.        action=Purge;
  275.        argv[i]=NULL;
  276.        continue;
  277.       }
  278.     if(!strcmp(argv[i],"-kill"))
  279.       {
  280.        if(action!=None)
  281.          {fprintf(stderr,"wwwoffle: Only one command at a time.nn");usage(0);}
  282.        action=Kill;
  283.        argv[i]=NULL;
  284.        continue;
  285.       }
  286.     if(argv[i][0]=='-' && argv[i][1])
  287.       {
  288.        fprintf(stderr,"wwwoffle: Unknown option '%s'.nn",argv[i]);
  289.        usage(0);
  290.       }
  291.     add_url_file(argv[i]);
  292.    }
  293.  if(action==None)
  294.     action=Get;
  295.  if((action==Post || action==Put) && n_url_file_list>1)
  296.    {
  297.     fprintf(stderr,"wwwoffle: The -post and -put options only allow one URL.nn");
  298.     usage(0);
  299.    }
  300.  /* Initialise things. */
  301.  if(!ConfigFile && !host && (env=getenv("WWWOFFLE_PROXY")))
  302.    {
  303.     if(*env=='/')
  304.        ConfigFile=env;
  305.     else
  306.       {
  307.        char *colon1,*colon2;
  308.        host=(char*)malloc(strlen(env)+1);
  309.        strcpy(host,env);
  310.        if((colon1=strchr(host,':')))
  311.          {
  312.           *colon1=0;
  313.           if((colon2=strchr(colon1+1,':')))
  314.             {
  315.              *colon2=0;
  316.              if(action==Get || action==Output || action==OutputWithHeader)
  317.                 port=atoi(colon1+1);
  318.              else
  319.                 port=atoi(colon2+1);
  320.             }
  321.           else
  322.              port=atoi(colon1+1);
  323.           if(port<=0 || port>=65536)
  324.             {fprintf(stderr,"wwwoffle: The port number %d '%s' is invalid.n",port,env); exit(1);}
  325.          }
  326.       }
  327.    }
  328.  InitErrorHandler("wwwoffle",0,1);
  329.  if(ConfigFile)
  330.    {
  331.     if(ReadConfigFile(2))
  332.        PrintMessage(Fatal,"Error in configuration file '%s'.",ConfigFile);
  333.     host=GetLocalHost(0);
  334.    }
  335.  /* The connections to the WWWOFFLE server. */
  336.  if(action!=Get && action!=Post && action!=Put && action!=Output && action!=OutputWithHeader)
  337.    {
  338.     int socket;
  339.     char *line=NULL;
  340.     socket=OpenClientSocket(host?host:"localhost",port?port:WWWOFFLE_Port,ConnectTimeout);
  341.     init_buffer(socket);
  342.     if(socket==-1)
  343.        PrintMessage(Fatal,"Cannot open connection to wwwoffle server %s port %d.",host?host:"localhost",port?port:WWWOFFLE_Port);
  344.     /* Send the message. */
  345.     if(PassWord)
  346.        write_formatted(socket,"WWWOFFLE PASSWORD %srn",PassWord);
  347.     if(action==Online)
  348.        write_string(socket,"WWWOFFLE ONLINErn");
  349.     else if(action==Autodial)
  350.        write_string(socket,"WWWOFFLE AUTODIALrn");
  351.     else if(action==Offline)
  352.        write_string(socket,"WWWOFFLE OFFLINErn");
  353.     else if(action==Fetch)
  354.        write_string(socket,"WWWOFFLE FETCHrn");
  355.     else if(action==Config)
  356.        write_string(socket,"WWWOFFLE CONFIGrn");
  357.     else if(action==Purge)
  358.        write_string(socket,"WWWOFFLE PURGErn");
  359.     else if(action==Kill)
  360.        write_string(socket,"WWWOFFLE KILLrn");
  361.     else
  362.        write_string(socket,"WWWOFFLE BOGUSrn");
  363.     while((line=read_line(socket,line)))
  364.       {
  365.        fputs(line,stdout);
  366.        fflush(stdout);
  367.       }
  368.     CloseSocket(socket);
  369.    }
  370.  /* The connections to the http proxy. */
  371.  else if(action==Get)
  372.    {
  373.     URL *Url;
  374.     struct stat buf;
  375.     char *refresh=NULL;
  376.     if(recursive_depth || recursive_mode || force || stylesheets || images || frames || scripts || objects)
  377.        refresh=CreateRefreshPath(recursive_depth,recursive_mode,force,
  378.                                  stylesheets,images,frames,scripts,objects);
  379.     for(i=0;i<n_url_file_list;i++)
  380.        if(strcmp(url_file_list[i],"-") && stat(url_file_list[i],&buf))
  381.          {
  382.           int socket;
  383.           char buffer[READ_BUFFER_SIZE];
  384.           socket=OpenClientSocket(host?host:"localhost",port?port:HTTP_Port,ConnectTimeout);
  385.           init_buffer(socket);
  386.           if(socket==-1)
  387.              PrintMessage(Fatal,"Cannot open connection to wwwoffle server %s port %d.",host?host:"localhost",port?port:HTTP_Port);
  388.           Url=SplitURL(url_file_list[i]);
  389.           if(refresh)
  390.              printf("Getting: %s (with recursive options).n",Url->name);
  391.           else
  392.              printf("Getting: %sn",Url->name);
  393.           if(Url->user)
  394.             {
  395.              char *userpass1=(char*)(malloc(strlen(Url->user)+(Url->pass?strlen(Url->pass):1)+3)),*userpass2;
  396.              sprintf(userpass1,"%s:%s",Url->user,Url->pass?Url->pass:"");
  397.              userpass2=Base64Encode(userpass1,strlen(userpass1));
  398.              if(refresh)
  399.                 write_formatted(socket,"GET %s/?%s HTTP/1.0rn"
  400.                                        "Authorization: Basic %srn"
  401.                                        "Pragma: wwwofflern"
  402.                                        "Accept: */*rn"
  403.                                        "rn",
  404.                                 refresh,Url->name,userpass2);
  405.              else
  406.                 write_formatted(socket,"GET %s HTTP/1.0rn"
  407.                                        "Authorization: Basic %srn"
  408.                                        "Pragma: wwwofflern"
  409.                                        "Accept: */*rn"
  410.                                        "rn",
  411.                                 Url->name,userpass2);
  412.              free(userpass1);
  413.              free(userpass2);
  414.             }
  415.           else
  416.             {
  417.              if(refresh)
  418.                 write_formatted(socket,"GET %s/?%s HTTP/1.0rn"
  419.                                        "Pragma: wwwofflern"
  420.                                        "Accept: */*rn"
  421.                                        "rn",
  422.                                 refresh,Url->name);
  423.              else
  424.                 write_formatted(socket,"GET %s HTTP/1.0rn"
  425.                                        "Pragma: wwwofflern"
  426.                                        "Accept: */*rn"
  427.                                        "rn",
  428.                                 Url->name);
  429.             }
  430.           while(read_data(socket,buffer,READ_BUFFER_SIZE)>0)
  431.              ;
  432.           CloseSocket(socket);
  433.           FreeURL(Url);
  434.          }
  435.        else if(!strcmp(url_file_list[i],"-") || S_ISREG(buf.st_mode))
  436.          {
  437.           int file;
  438.           char *buffer=(char*)malloc(strlen(url_file_list[i])+256);
  439.           char **links;
  440.           if(strcmp(url_file_list[i],"-"))
  441.             {
  442.              file=open(url_file_list[i],O_RDONLY);
  443.              if(file==-1)
  444.                {PrintMessage(Warning,"Cannot open file '%s' for reading.",url_file_list[i]);continue;}
  445.              printf("Reading: %sn",url_file_list[i]);
  446.             }
  447.           else
  448.             {
  449.              file=fileno(stdin);
  450.              printf("Reading: <stdin>n");
  451.             }
  452.           init_buffer(file);
  453.           strcpy(buffer,"file://localhost");
  454.           if(*url_file_list[i]=='/')
  455.              strcat(buffer,url_file_list[i]);
  456.           else
  457.             {
  458.              char cwd[PATH_MAX+1];
  459.              if(!getcwd(cwd,PATH_MAX))
  460.              cwd[0]=0;
  461.              strcat(buffer,cwd);
  462.              strcat(buffer,"/");
  463.              strcat(buffer,url_file_list[i]);
  464.             }
  465.           Url=SplitURL(buffer);
  466.           ParseHTML(file,Url);
  467.           if(stylesheets && (links=GetReferences(RefStyleSheet)))
  468.              add_url_list(links);
  469.           if(images && (links=GetReferences(RefImage)))
  470.              add_url_list(links);
  471.           if(frames && (links=GetReferences(RefFrame)))
  472.              add_url_list(links);
  473.           if(scripts && (links=GetReferences(RefScript)))
  474.              add_url_list(links);
  475.           if(objects && (links=GetReferences(RefObject)))
  476.              add_url_list(links);
  477.           if(objects && (links=GetReferences(RefInlineObject)))
  478.              add_url_list(links);
  479.           if((links=GetReferences(RefLink)))
  480.              add_url_list(links);
  481.           FreeURL(Url);
  482.           free(buffer);
  483.           if(file!=0)
  484.              close(file);
  485.          }
  486.        else
  487.           PrintMessage(Warning,"The file '%s' is not a regular file.",url_file_list[i]);
  488.    }
  489.  else if(action==Post || action==Put)
  490.    {
  491.     URL *Url;
  492.     int socket,n,length=0;
  493.     char buffer[READ_BUFFER_SIZE];
  494.     char *data=(char*)malloc(READ_BUFFER_SIZE+1);
  495.     socket=OpenClientSocket(host?host:"localhost",port?port:HTTP_Port,ConnectTimeout);
  496.     init_buffer(socket);
  497.     if(socket==-1)
  498.        PrintMessage(Fatal,"Cannot open connection to wwwoffle server %s port %d.",host?host:"localhost",port?port:HTTP_Port);
  499.     Url=SplitURL(url_file_list[0]);
  500.     if(action==Post)
  501.        printf("Posting: %sn",Url->name);
  502.     else
  503.        printf("Putting: %sn",Url->name);
  504.     while((n=read_data(0,data+length,READ_BUFFER_SIZE))>0)
  505.       {
  506.        length+=n;
  507.        data=(char*)realloc((void*)data,length+READ_BUFFER_SIZE+1);
  508.       }
  509.     if(Url->user)
  510.       {
  511.        char *userpass1=(char*)(malloc(strlen(Url->user)+(Url->pass?strlen(Url->pass):1)+3)),*userpass2;
  512.        sprintf(userpass1,"%s:%s",Url->user,Url->pass?Url->pass:"");
  513.        userpass2=Base64Encode(userpass1,strlen(userpass1));
  514.        if(action==Post)
  515.           write_formatted(socket,"POST %s HTTP/1.0rn"
  516.                                  "Authorization: Basic %srn"
  517.                                  "Content-Type: application/x-www-form-urlencodedrn"
  518.                                  "Content-Length: %drn"
  519.                                  "Pragma: wwwofflern"
  520.                                  "Accept: */*rn"
  521.                                  "rn",
  522.                           Url->name,userpass2,length);
  523.        else
  524.           write_formatted(socket,"PUT %s HTTP/1.0rn"
  525.                                  "Authorization: Basic %srn"
  526.                                  "Content-Length: %drn"
  527.                                  "Pragma: wwwofflern"
  528.                                  "Accept: */*rn"
  529.                                  "rn",
  530.                           Url->name,userpass2,length);
  531.        free(userpass1);
  532.        free(userpass2);
  533.       }
  534.     else
  535.       {
  536.        if(action==Post)
  537.           write_formatted(socket,"POST %s HTTP/1.0rn"
  538.                                  "Content-Type: application/x-www-form-urlencodedrn"
  539.                                  "Content-Length: %drn"
  540.                                  "Pragma: wwwofflern"
  541.                                  "Accept: */*rn"
  542.                                  "rn",
  543.                           Url->name,length);
  544.        else
  545.           write_formatted(socket,"PUT %s HTTP/1.0rn"
  546.                                  "Content-Length: %drn"
  547.                                  "Pragma: wwwofflern"
  548.                                  "Accept: */*rn"
  549.                                  "rn",
  550.                           Url->name,length);
  551.       }
  552.     write_data(socket,data,length);
  553.     write_data(socket,"rn",2);
  554.     while(read_data(socket,buffer,READ_BUFFER_SIZE)>0)
  555.        ;
  556.     CloseSocket(socket);
  557.     FreeURL(Url);
  558.     free(data);
  559.    }
  560.  else /* action==Output or action==OutputWithHeader */
  561.    {
  562.     URL *Url;
  563.     int socket;
  564.     char *line=NULL,buffer[READ_BUFFER_SIZE];
  565.     int nbytes;
  566.     if(!n_url_file_list)
  567.        PrintMessage(Fatal,"No URL specified to output.");
  568.     socket=OpenClientSocket(host?host:"localhost",port?port:HTTP_Port,ConnectTimeout);
  569.     init_buffer(socket);
  570.     if(socket==-1)
  571.        PrintMessage(Fatal,"Cannot open connection to wwwoffle server %s port %d.",host?host:"localhost",port?port:HTTP_Port);
  572.     Url=SplitURL(url_file_list[0]);
  573.     if(action!=Output && action!=OutputWithHeader)
  574.        fprintf(stderr,"Getting: %sn",Url->name);
  575.     if(Url->user)
  576.       {
  577.        char *userpass1=(char*)(malloc(strlen(Url->user)+(Url->pass?strlen(Url->pass):1)+3)),*userpass2;
  578.        sprintf(userpass1,"%s:%s",Url->user,Url->pass?Url->pass:"");
  579.        userpass2=Base64Encode(userpass1,strlen(userpass1));
  580.        write_formatted(socket,"GET %s HTTP/1.0rn"
  581.                               "Authorization: Basic %srn"
  582.                               "Pragma: wwwofflern"
  583.                               "Accept: */*rn"
  584.                               "rn",
  585.                        Url->name,userpass2);
  586.        free(userpass1);
  587.        free(userpass2);
  588.       }
  589.     else
  590.        write_formatted(socket,"GET %s HTTP/1.0rn"
  591.                               "Pragma: wwwofflern"
  592.                               "Accept: */*rn"
  593.                               "rn",
  594.                        Url->name);
  595.     if((line=read_line(socket,line)))
  596.       {
  597.        char *willget="HTTP/1.0 404 WWWOFFLE Will Getrn";
  598.        int status;
  599.        sscanf(line,"%*s %d",&status);
  600.        if(!strcmp(willget,line))
  601.           fprintf(stderr,"The URL is not in the cache but has been requested.n");
  602.        else if((status>=300 && status<400) && action!=OutputWithHeader)
  603.           fprintf(stderr,"The URL has been moved, check with a browser.n");
  604.        else if(status!=200 && action!=OutputWithHeader)
  605.           fprintf(stderr,"The URL returns an error message, check with a browser.n");
  606.        else
  607.          {
  608.           if(action==OutputWithHeader)
  609.              fputs(line,stdout);
  610.           while((line=read_line(socket,line)))
  611.             {
  612.              if(action==OutputWithHeader)
  613.                 fputs(line,stdout);
  614.              if(line[0]=='r' || line[0]=='n')
  615.                 break;
  616.             }
  617.           while((nbytes=read_data(socket,buffer,READ_BUFFER_SIZE))>0)
  618.              fwrite(buffer,1,nbytes,stdout);
  619.          }
  620.       }
  621.     else
  622.        PrintMessage(Fatal,"Cannot read from wwwoffle server.");
  623.     CloseSocket(socket);
  624.     FreeURL(Url);
  625.    }
  626.  /* exit. */
  627.  return(0);
  628. }
  629. /*++++++++++++++++++++++++++++++++++++++
  630.   Print the program usage in long or short format.
  631.   int verbose True for long format.
  632.   ++++++++++++++++++++++++++++++++++++++*/
  633. static void usage(int verbose)
  634. {
  635.  fprintf(stderr,
  636.          "n"
  637.          "WWWOFFLE - World Wide Web Offline Explorer - Version %sn"
  638.          "n",WWWOFFLE_VERSION);
  639.  if(verbose)
  640.     fprintf(stderr,
  641.             "(c) Andrew M. Bishop 1996,97,98,99 [       amb@gedanken.demon.co.uk ]n"
  642.             "                                   [http://www.gedanken.demon.co.uk/]n"
  643.             "n");
  644.  fprintf(stderr,
  645.          "Usage: wwwoffle -hn"
  646.          "       wwwoffle -online | -autodial | -offline | -fetchn"
  647.          "       wwwoffle -config | -purge | -killn"
  648.          "       wwwoffle [-o|-O] <url>n"
  649.          "       wwwoffle [-g[Sisfo]] [-F] [-(d|r|R)[<depth>]] <url> ...n"
  650.          "       wwwoffle [-g[Sisfo]] [-F] [-(d|r|R)[<depth>]] [<file>|-] ...n"
  651.          "       wwwoffle -post <url> | -put <url>n"
  652.          "n"
  653.          "Any of these can also take:  [-p <host>[:<port>] | -c <config-file>]n"
  654.          "The environment variable WWWOFFLE_PROXY can be set instead of -p or -c options.n"
  655.          "n");
  656.  if(verbose)
  657.     fprintf(stderr,
  658.             "wwwoffle -h          : Display this help.n"
  659.             "n"
  660.             "wwwoffle -on[line]   : Indicate to the server that the network is active.n"
  661.             "                       (Proxy requests will be fetched from remote hosts.)n"
  662.             "n"
  663.             "wwwoffle -auto[dial] : Indicate to the server that the network is automatic.n"
  664.             "                       (Proxy requests will be fetched from remote hostsn"
  665.             "                        ONLY if they are not already cached.)n"
  666.             "n"
  667.             "wwwoffle -off[line]  : Indicate to the server that the network is inactive.n"
  668.             "                       (Proxy requests will be fetched from cache or recorded.)n"
  669.             "n"
  670.             "wwwoffle -fetch      : Force the server to fetch the pages that are recorded.n"
  671.             "n"
  672.             "wwwoffle -config     : Force the server to re-read the configuration file.n"
  673.             "n"
  674.             "wwwoffle -purge      : Force the server to purge pages from the cache.n"
  675.             "n"
  676.             "wwwoffle -kill       : Force the server to exit cleanly.n"
  677.             "n"
  678.             "wwwoffle <url> ...   : Fetch the specified URLs.n"
  679.             "n"
  680.             "wwwoffle <file> ...  : Fetch the URLs that are links in the specified file.n"
  681.             "n"
  682.             " -o                  : Fetch the URL and output it on the standard output.n"
  683.             " -O                  : As above but include the HTTP header.n"
  684.             "n"
  685.             " -g[Sisfo]           : Fetch the items included in the specified URLs.n"
  686.             "                       (S=stylesheets, i=images, f=frames, s=scripts, o=objects)n"
  687.             " -F                  : Force the url to be refreshed even if already cached.n"
  688.             " -(d|r|R)[<depth>]   : Fetch pages linked to the URLs and their links,n"
  689.             "                       going no more than <depth> steps (default 1).n"
  690.             "                        (-d => URLs in the same directory or sub-directory)n"
  691.             "                        (-r => URLs on the same host)n"
  692.             "                        (-R => URLs on any host)n"
  693.             "n"
  694.             "wwwoffle -post <url> : Create a request using the POST method, the data is readn"
  695.             "                       from stdin and appended to the request.  The user shouldn"
  696.             "                       ensure that the data is correctly url-encoded.n"
  697.             "wwwoffle -put <url>  : Create a request using the PUT method, the data is readn"
  698.             "                       from stdin and appended to the request.n"
  699.             "n"
  700.             " -p <host>[:<port>]  : The host name and port number to talk to the demon on.n"
  701.             "                       (Defaults to localhost for the server andn"
  702.             "                        %d for control port, %d for http proxy port).n"
  703.             "n"
  704.             " -c <config-file>    : The name of the configuration file with the hostname,n"
  705.             "                       port number and the password (if any).n"
  706.             "n"
  707.             "WWWOFFLE_PROXY       : An environment variable that can be set to either then"
  708.             "                       name of the config file (absolute path) or the hostnamen"
  709.             "                       and port number (both proxy and control) for the proxy.n"
  710.             "                       e.g. "/var/spool/wwwoffle/wwwoffle.conf",n"
  711.             "                       "localhost:8080:8081" or "localhost:8080" are valid.n"
  712.             "n",DEF_WWWOFFLE_PORT,DEF_HTTP_PORT);
  713.  if(verbose)
  714.     exit(0);
  715.  else
  716.     exit(1);
  717. }
  718. /*++++++++++++++++++++++++++++++++++++++
  719.   Add a list of URLs to the list.
  720.   char **links The list of URLs to add.
  721.   ++++++++++++++++++++++++++++++++++++++*/
  722. static void add_url_list(char **links)
  723. {
  724.  int i;
  725.  for(i=0;links[i];i++)
  726.    {
  727.     URL *linkUrl=SplitURL(links[i]);
  728.     if(strcmp(linkUrl->proto,"file"))
  729.        add_url_file(linkUrl->name);
  730.     FreeURL(linkUrl);
  731.    }
  732. }
  733. /*++++++++++++++++++++++++++++++++++++++
  734.   Add a URL or a file to the list.
  735.   char *url_file The URL or file to add.
  736.   ++++++++++++++++++++++++++++++++++++++*/
  737. static void add_url_file(char *url_file)
  738. {
  739.  if(!(n_url_file_list%16))
  740.    {
  741.     if(n_url_file_list)
  742.        url_file_list=(char**)realloc(url_file_list,(n_url_file_list+16)*sizeof(char*));
  743.     else
  744.        url_file_list=(char**)malloc(16*sizeof(char*));
  745.    }
  746.  url_file_list[n_url_file_list]=(char*)malloc(strlen(url_file)+1);
  747.  strcpy(url_file_list[n_url_file_list],url_file);
  748.  n_url_file_list++;
  749. }