home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Magazine / wwwoffle-2.1.tar.gz / wwwoffle-2.1 / configedit.c < prev    next >
C/C++ Source or Header  |  1998-02-12  |  13KB  |  496 lines

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/configedit.c 2.8 1998/01/28 18:42:42 amb Exp $
  3.  
  4.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.1.
  5.   Configuration file management via a web-page.
  6.   ******************/ /******************
  7.   Written by Andrew M. Bishop
  8.  
  9.   This file Copyright 1997,98 Andrew M. Bishop
  10.   It may be distributed under the GNU Public License, version 2, or
  11.   any higher version.  See section COPYING of the GNU Public license
  12.   for conditions under which this file may be redistributed.
  13.   ***************************************/
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #include <sys/stat.h>
  20. #include <unistd.h>
  21.  
  22. #include "wwwoffle.h"
  23. #include "misc.h"
  24. #include "config.h"
  25. #include "errors.h"
  26.  
  27.  
  28. static void ConfigEditForms(int fd,char ***sections);
  29. static void ConfigEditUpdate(int fd,char *section,char ***sections);
  30. static void ConfigEditError(int fd,char *msg);
  31.  
  32. static char ***read_config_file(void);
  33. static int write_config_file(char ***sections);
  34. static void free_sections(char ***sections);
  35.  
  36.  
  37. /*++++++++++++++++++++++++++++++++++++++
  38.   The control page that allows editing of the configuration file.
  39.  
  40.   int fd The file descriptor to write the file to.
  41.  
  42.   char *args The arguments to the page.
  43.  
  44.   char *request_body The body of the HTTP request for the page.
  45.   ++++++++++++++++++++++++++++++++++++++*/
  46.  
  47. void ConfigEditPage(int fd,char *args,char *request_body)
  48. {
  49.  char *newargs=NULL;
  50.  char ***sections;
  51.  
  52.  if(args)
  53.    {
  54.     if(*args=='!' && strchr(args+1,'!'))
  55.       {
  56.        char *pling;
  57.        newargs=(char*)malloc(strlen(args)+1);
  58.        strcpy(newargs,args+1);
  59.        pling=strchr(newargs,'!');
  60.        *pling=0;
  61.       }
  62.     else if(*args!='!')
  63.       {
  64.        newargs=(char*)malloc(strlen(args)+1);
  65.        strcpy(newargs,args);
  66.       }
  67.    }
  68.  
  69.  sections=read_config_file();
  70.  
  71.  if(!sections)
  72.    {
  73.     char *error=
  74.     "Could not open the configuration file <tt>%s</tt> for reading.\n"
  75.     "<p>\n"
  76.     "<b>OR</b>\n"
  77.     "<p>\n"
  78.     "There was a parse error in reading the configuration file <tt>%s</tt>.";
  79.     char *message;
  80.     message=(char*)malloc(strlen(error)+2*strlen(ConfigFile)+1);
  81.     sprintf(message,error,ConfigFile,ConfigFile);
  82.     ConfigEditError(fd,message);
  83.     free(message);
  84.    }
  85.  else if(newargs && *newargs)
  86.    {
  87.     int i=0;
  88.     char *section=NULL;
  89.  
  90.     while(sections[i])
  91.       {
  92.        if(sections[i][1] && !strcmp(sections[i][1],newargs))
  93.          {section=newargs;break;}
  94.        i++;
  95.       }
  96.  
  97.     if(!section)
  98.       {
  99.        char *error=
  100.        "The specfied URL <tt>/control/edit?%s</tt> does not correspond to a section in the configuration file <tt>%s</tt>.\n";
  101.        char *message;
  102.        message=(char*)malloc(strlen(error)+strlen(newargs)+strlen(ConfigFile)+1);
  103.        sprintf(message,error,newargs,ConfigFile);
  104.        ConfigEditError(fd,message);
  105.        free(message);
  106.       }
  107.     else if(!request_body || strncmp(request_body,"value=",6))
  108.        ConfigEditError(fd,"The body of the reply was missing or invalid");
  109.     else
  110.       {
  111.        char *new,*p,*q;
  112.  
  113.        new=UrlDecode(request_body+6,1);
  114.        for(p=q=new;*p;p++)
  115.           if(*p!='\r')
  116.              *q++=*p;
  117.        *q=0;
  118.  
  119.        sections[i][2]=new;
  120.  
  121.        ConfigEditUpdate(fd,section,sections);
  122.       }
  123.    }
  124.  else
  125.     ConfigEditForms(fd,sections);
  126.  
  127.  if(sections)
  128.     free_sections(sections);
  129.  
  130.  if(newargs)
  131.     free(newargs);
  132. }
  133.  
  134.  
  135. /*++++++++++++++++++++++++++++++++++++++
  136.   The page that contains the forms making up the config file.
  137.  
  138.   int fd The file descriptor to write to.
  139.  
  140.   char ***sections The sections of the file.
  141.   ++++++++++++++++++++++++++++++++++++++*/
  142.  
  143. static void ConfigEditForms(int fd,char ***sections)
  144. {
  145.  char *head=
  146.  "HTTP/1.0 200 WWWOFFLE Configuration Page\r\n"
  147.  "Content-type: text/html\r\n"
  148.  "\r\n"
  149.  "<HTML>\n"
  150.  "<HEAD>\n"
  151.  "<TITLE>WWWOFFLE - Interactive Configuration Page</TITLE>\n"
  152.  "</HEAD>\n"
  153.  "<BODY>\n"
  154.  "<H1 align=center>WWWOFFLE Interactive Configuration Page</H1>\n\n";
  155.  char *sectionhead=
  156.  "\n<h2>%s Section</h2>\n\n";
  157.  char *commenthead=
  158.  "\n<h2>Body Comment</h2>\n\n";
  159.  char *formhead=
  160.  "<form action=\"/control/edit?%s\" method=post>\n"
  161.  "<textarea name=\"value\" cols=60 rows=10>";
  162.  char *formtail=
  163.  "</textarea>\n"
  164.  "<br>\n"
  165.  "<input type=\"submit\" value=\"Update\"><input type=\"reset\" value=\"Reset\">\n"
  166.  "</form>\n";
  167.  char *tail=
  168.  "<h1>Re-Read Configuration File</h1>\n\n"
  169.  "<form action=\"/control/config\" method=post>\n"
  170.  "<input type=\"hidden\" name=action value=\"config\">\n"
  171.  "<input type=\"submit\" value=\"Config\"> Force <b>wwwoffled</b> to re-read the configuration file.\n"
  172.  "</form>\n"
  173.  "<p align=center>[<a href=\"/control/\">Back to the Control page</a>]</p>\n"
  174.  "</BODY>\n"
  175.  "</HTML>\n";
  176.  int i=0;
  177.  
  178.  write_string(fd,head);
  179.  
  180.  if(sections[i] && sections[i][0])
  181.    {
  182.     char *safe=HTMLString(sections[i][0]);
  183.     write_string(fd,"<pre>\n");
  184.     write_string(fd,safe);
  185.     write_string(fd,"</pre>\n\n");
  186.     free(safe);
  187.    }
  188.  
  189.  while(sections[++i])
  190.    {
  191.     if(sections[i][1])
  192.       {
  193.        write_formatted(fd,sectionhead,sections[i][1]);
  194.  
  195.        if(sections[i][0])
  196.          {
  197.           char *safe=HTMLString(sections[i][0]);
  198.           write_string(fd,"<pre>\n");
  199.           write_string(fd,safe);
  200.           write_string(fd,"</pre>\n\n");
  201.           free(safe);
  202.          }
  203.  
  204.        write_formatted(fd,formhead,sections[i][1]);
  205.  
  206.        write_string(fd,sections[i][2]);
  207.  
  208.        write_string(fd,formtail);
  209.       }
  210.     else
  211.       {
  212.        char *safe=HTMLString(sections[i][0]);
  213.  
  214.        write_string(fd,commenthead);
  215.  
  216.        write_string(fd,"<pre>\n");
  217.        write_string(fd,safe);
  218.        write_string(fd,"</pre>\n\n");
  219.        free(safe);
  220.       }
  221.    }
  222.  
  223.  write_string(fd,tail);
  224. }
  225.  
  226.  
  227. /*++++++++++++++++++++++++++++++++++++++
  228.   Update the configuration file.
  229.  
  230.   int fd The file descriptor to write the message to.
  231.  
  232.   char *section The section that was updated.
  233.  
  234.   char ***sections The sections including the updated one.
  235.   ++++++++++++++++++++++++++++++++++++++*/
  236.  
  237. static void ConfigEditUpdate(int fd,char *section,char ***sections)
  238. {
  239.  char *head=
  240.  "HTTP/1.0 200 WWWOFFLE Configuration Update Page\r\n"
  241.  "Content-type: text/html\r\n"
  242.  "\r\n"
  243.  "<HTML>\n"
  244.  "<HEAD>\n"
  245.  "<TITLE>WWWOFFLE - Interactive Configuration Update Page</TITLE>\n"
  246.  "</HEAD>\n"
  247.  "<BODY>\n"
  248.  "<H1 align=center>WWWOFFLE Interactive Configuration Update Page</H1>\n\n";
  249.  char *middle=
  250.  "The <b>%s</b> section of the configuration file <tt>%s</tt> has been updated.";
  251.  char *tail=
  252.  "<p align=center>[<a href=\"/control/edit/\">Back to the Configuration Edit page</a>]</p>\n"
  253.  "</BODY>\n"
  254.  "</HTML>\n";
  255.  
  256.  if(write_config_file(sections))
  257.    {
  258.     char *error="Could not open the configuration file <tt>%s</tt> for writing";
  259.     char *message;
  260.     message=(char*)malloc(strlen(error)+strlen(ConfigFile)+1);
  261.     sprintf(message,error,ConfigFile);
  262.     ConfigEditError(fd,message);
  263.     free(message);
  264.    }
  265.  else
  266.    {
  267.     char *message;
  268.     write_string(fd,head);
  269.  
  270.     message=(char*)malloc(strlen(middle)+strlen(section)+strlen(ConfigFile)+1);
  271.     sprintf(message,middle,section,ConfigFile);
  272.     write_string(fd,message);
  273.     free(message);
  274.  
  275.     write_string(fd,tail);
  276.    }
  277. }
  278.  
  279.  
  280. /*++++++++++++++++++++++++++++++++++++++
  281.   The error message if the ConfigFile cannot be parsed.
  282.  
  283.   int fd The file descriptor to write to.
  284.  
  285.   char *msg The message to print on the error page.
  286.   ++++++++++++++++++++++++++++++++++++++*/
  287.  
  288. static void ConfigEditError(int fd,char *msg)
  289. {
  290.  char *head=
  291.  "HTTP/1.0 404 WWWOFFLE Configuration Edit Error\r\n"
  292.  "Content-type: text/html\r\n"
  293.  "\r\n"
  294.  "<HTML>\n"
  295.  "<HEAD>\n"
  296.  "<TITLE>WWWOFFLE - Interactive Configuration Error Page</TITLE>\n"
  297.  "</HEAD>\n"
  298.  "<BODY>\n"
  299.  "<H1 align=center>WWWOFFLE Interactive Configuration Error Page</H1>\n\n";
  300.  char *tail=
  301.  "<p align=center>[<a href=\"/control/edit/\">Back to the Configuration Edit page</a>]</p>\n"
  302.  "</BODY>\n"
  303.  "</HTML>\n";
  304.  
  305.  write_string(fd,head);
  306.  write_string(fd,msg);
  307.  write_string(fd,tail);
  308. }
  309.  
  310.  
  311. /*++++++++++++++++++++++++++++++++++++++
  312.   Read in the config file into a set of sections.
  313.  
  314.   char ***read_config_file Returns the sections of the file.
  315.                            x[i][0]=comment, x[i][1]=section name, x[i][2]=section contents,
  316.                            the last x[i] is a NULL.
  317.   ++++++++++++++++++++++++++++++++++++++*/
  318.  
  319. static char ***read_config_file(void)
  320. {
  321.  int sec_num=0,state=0;
  322.  FILE *conf;
  323.  char ***sections;
  324.  char *line=NULL;
  325.  int line_num=0;
  326.  
  327.  conf=fopen(ConfigFile,"r");
  328.  if(!conf)
  329.    {PrintMessage(Warning,"Cannot open the config file '%s' for reading.",ConfigFile); return(NULL);}
  330.  
  331.  sections=(char***)calloc(1,sizeof(char**));
  332.  
  333.  while((line=fgets_realloc(line,conf)))
  334.    {
  335.     char *l=line;
  336.     char *r=line+strlen(line)-1;
  337.  
  338.     line_num++;
  339.  
  340.     while(*l==' ' || *l=='\t' || *l=='\r' || *l=='\n')
  341.        l++;
  342.  
  343.     if(state==0 && *l=='#')
  344.       {
  345.        state=1;
  346.        sections=(char***)realloc((void*)sections,sizeof(char**)*(sec_num+2));
  347.        sections[sec_num]=(char**)calloc(3,sizeof(char*));
  348.        sections[++sec_num]=NULL;
  349.        sections[sec_num-1][0]=(char*)malloc(strlen(l)+1);
  350.        strcpy(sections[sec_num-1][0],l);
  351.       }
  352.     else if((state==1 || state==2) && *l=='#')
  353.       {
  354.        sections[sec_num-1][0]=(char*)realloc((void*)sections[sec_num-1][0],strlen(sections[sec_num-1][0])+strlen(l)+1);
  355.        strcat(sections[sec_num-1][0],l);
  356.       }
  357.     else if(state==0 && !*l)
  358.       ;
  359.     else if(state==1 && !*l)
  360.        state=0;
  361.     else if((state==0 || state==1) && *l)
  362.       {
  363.        state=2;
  364.        while(r>l && (*r==' ' || *r=='\t' || *r=='\r' || *r=='\n'))
  365.           *r--=0;
  366.        if(sections[sec_num-1][1])
  367.          {
  368.           sections=(char***)realloc((void*)sections,sizeof(char**)*(sec_num+2));
  369.           sections[sec_num]=(char**)calloc(3,sizeof(char*));
  370.           sections[++sec_num]=NULL;
  371.          }
  372.        sections[sec_num-1][1]=(char*)malloc(strlen(l)+1);
  373.        strcpy(sections[sec_num-1][1],l);
  374.       }
  375.     else if(state==2 && !*l)
  376.       ;
  377.     else if(state==2 && *l=='{')
  378.       {
  379.        state=3;
  380.        sections[sec_num-1][2]=(char*)malloc(1);
  381.        strcpy(sections[sec_num-1][2],"");
  382.       }
  383.     else if(state==3 && *l=='}')
  384.        state=0;
  385.     else if(state==3)
  386.       {
  387.        sections[sec_num-1][2]=(char*)realloc((void*)sections[sec_num-1][2],strlen(sections[sec_num-1][2])+strlen(line)+1);
  388.        strcat(sections[sec_num-1][2],line);
  389.       }
  390.     else
  391.       {
  392.        line[strlen(line)-1]=0;
  393.        PrintMessage(Warning,"Error parsing config file, line %d = '%s' [state=%d]",line_num,line,state);
  394.        free_sections(sections);
  395.        return(NULL);
  396.       }
  397.    }
  398.  
  399.  fclose(conf);
  400.  
  401.  return(sections);
  402. }
  403.  
  404.  
  405. /*++++++++++++++++++++++++++++++++++++++
  406.   Write out a set of sections to the config file.
  407.  
  408.   int write_config_file Returns 1 if in error.
  409.  
  410.   char ***sections The sections to write out.
  411.   ++++++++++++++++++++++++++++++++++++++*/
  412.  
  413. static int write_config_file(char ***sections)
  414. {
  415.  char *conf_file_backup=(char*)malloc(strlen(ConfigFile)+5);
  416.  int renamed=0,i=0;
  417.  struct stat buf;
  418.  FILE *conf;
  419.  
  420.  /* Rename the old file as a backup. */
  421.  
  422.  strcpy(conf_file_backup,ConfigFile);
  423.  strcat(conf_file_backup,".old");
  424.  
  425.  if(rename(ConfigFile,conf_file_backup))
  426.     PrintMessage(Warning,"Cannot rename the config file '%s' to '%s'.",ConfigFile,conf_file_backup);
  427.  else
  428.    {
  429.     renamed=1;
  430.     if(stat(conf_file_backup,&buf))
  431.        PrintMessage(Warning,"Cannot stat the config file '%s'.",ConfigFile);
  432.    }
  433.  
  434.  conf=fopen(ConfigFile,"w");
  435.  if(!conf)
  436.    {PrintMessage(Warning,"Cannot open the config file '%s' for writing.",ConfigFile); return(1);}
  437.  
  438.  if(renamed)
  439.    {
  440.     chown(ConfigFile,buf.st_uid,buf.st_gid);
  441.     chmod(ConfigFile,buf.st_mode&(~S_IFMT));
  442.    }
  443.  
  444.  while(sections[i])
  445.    {
  446.     if(sections[i][0])
  447.       {
  448.        fprintf(conf,sections[i][0]);
  449.        fprintf(conf,"\n");
  450.       }
  451.     if(sections[i][1])
  452.       {
  453.        fprintf(conf,"%s\n",sections[i][1]);
  454.        fprintf(conf,"{\n");
  455.        if(sections[i][2])
  456.           fprintf(conf,sections[i][2]);
  457.        if(sections[i][2][strlen(sections[i][2])-1]!='\n')
  458.           fprintf(conf,"\n");
  459.        fprintf(conf,"}\n\n");
  460.       }
  461.     i++;
  462.    }
  463.  
  464.  fclose(conf);
  465.  
  466.  free(conf_file_backup);
  467.  
  468.  return(0);
  469. }
  470.  
  471.  
  472. /*++++++++++++++++++++++++++++++++++++++
  473.   Free up a set of sections.
  474.  
  475.   char ***sections The sections that are to be freed up.
  476.   ++++++++++++++++++++++++++++++++++++++*/
  477.  
  478. static void free_sections(char ***sections)
  479. {
  480.  int i=0;
  481.  
  482.  while(sections[i])
  483.    {
  484.     if(sections[i][0])
  485.        free(sections[i][0]);
  486.     if(sections[i][1])
  487.        free(sections[i][1]);
  488.     if(sections[i][2])
  489.        free(sections[i][2]);
  490.     free(sections[i]);
  491.     i++;
  492.    }
  493.  
  494.  free(sections);
  495. }
  496.