/*
 *  CiWiki is a fork of DidiWiki - a small lightweight wiki engine. 
 *  CiWiki Copyright 2010-2015 Jean-Pierre Redonnet <inphilly@gmail.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

#include "ci.h"
#include "wikitext.h"
#include "wikilogin.h"
#include "wikichanges.h"
#include "wikiashtml.h"
#include "wikientries.h"

/* local variable */
static int errorcnt=0;
static char* CssData = STYLESHEET; //default css data are in wikitext.h
static char* EditHeader = EDITHEADER;
static char* PageHeader = PAGEHEADER;
static char* ShortHelp = SHORTHELP;
static char* LogInForm = LOGINFORM;
static char* LogInForm2 = LOGINFORM2;
static char* NewLogInForm = NEWLOGINFORM;
//static char* ChgPwdForm = CHGPWDFORM; //?
static char* LogInfo = LOGINFO;
static char* CreateForm = CREATEFORM;
static char* EditForm = EDITFORM;
static char* DeleteForm = DELETEFORM;
static char* HomeRedirect = HOMEREDIRECT;

static char *msgList[30] = { "", MSG01, MSG02, MSG03, MSG04, MSG05, MSG06, MSG07, MSG08, 
  MSG09, MSG10, MSG11, MSG12, MSG13, MSG14, MSG15, MSG16, MSG17, MSG18, MSG19, MSG20, 
  MSG21, MSG22, MSG23, MSG24, MSG25, MSG26, MSG27 };

/* external variable */
extern long int upload_status;
extern int lgindex;
extern int Exec_allowed;
extern int Upload_allowed;
extern int indexShowWhat;
extern int secureLogin;
extern char* secureKey; 
      

int loginform;

/* read wiki page, styles.css, header, forms and allocate enough mem 
 * don't forget to free() the allocated memory */
static char *
file_read(char *filename)
{
  struct stat st;
  FILE*       fp;
  char*       str;
  int         len;

  /* Get the file size. */
  if (stat(filename, &st)) 
    return NULL;

  if (!(fp = fopen(filename, "rb"))) 
    return NULL;
  
  str = (char *)malloc(sizeof(char)*(st.st_size + 1));
  len = fread(str, 1, st.st_size, fp);
  if (len >= 0) str[len] = '\0';
  
  fclose(fp);

  return str;
}

/* save wiki page */
static int
file_write(char *filename, char *data)
{
  FILE*       fp;
  int         bytes_written = 0;
  int         len           = strlen(data); /* clip off extra '\0' */
  char        filename_prev[strlen(filename)+10];
  char        *str_ptr;

  /* replace each space between 2 words with an underline */
  while ( (str_ptr=strchr(filename,' ')) )
    *str_ptr='_';

  /* page will be restored */
  if ( strstr(filename,".prev.1") )
  {
    /* previous page restored as current page */
    strcpy(filename_prev,filename);
    *strstr(filename,".prev.1")='\0'; //remove ext
    rename(filename,filename_prev);
  }
  else
  {
    /* backup the previous page */
    strcpy(filename_prev,filename);
    strcat(filename_prev,".prev.1");
    rename(filename,filename_prev);
  }
  
  if (!(fp = fopen(filename, "wb"))) 
    return -1;
 
  while ( len > 0 )
    {
      bytes_written = fwrite(data, sizeof(char), len, fp);
      len = len - bytes_written;
      data = data + bytes_written;
    }

  fclose(fp);

  return 1;
}

/*
 * Save messages
*/
static int
file_writeMsg(char *filename)
{
  FILE*   fp;
  if (!(fp = fopen(filename, "w"))) 
    return -1;
  
  fprintf(fp, "#Autogenerated by ciwiki.\n\n");
  fprintf(fp, "MSG01\n%s\n/MSG\n\n",  MSG01);
  fprintf(fp, "MSG02\n%s\n/MSG\n\n",  MSG02);
  fprintf(fp, "MSG03\n%s\n/MSG\n\n",  MSG03);
  fprintf(fp, "MSG04\n%s\n/MSG\n\n",  MSG04);
  fprintf(fp, "MSG05\n%s\n/MSG\n\n",  MSG05);  
  fprintf(fp, "MSG06\n%s\n/MSG\n\n",  MSG06);
  fprintf(fp, "MSG07\n%s\n/MSG\n\n",  MSG07);
  fprintf(fp, "MSG08\n%s\n/MSG\n\n",  MSG08);
  fprintf(fp, "MSG09\n%s\n/MSG\n\n",  MSG09);
  fprintf(fp, "MSG10\n%s\n/MSG\n\n",  MSG10);
  fprintf(fp, "MSG11\n%s\n/MSG\n\n",  MSG11);
  fprintf(fp, "MSG12\n%s\n/MSG\n\n",  MSG12);
  fprintf(fp, "MSG13\n%s\n/MSG\n\n",  MSG13);
  fprintf(fp, "MSG14\n%s\n/MSG\n\n",  MSG14);
  fprintf(fp, "MSG15\n%s\n/MSG\n\n",  MSG15);  
  fprintf(fp, "MSG16\n%s\n/MSG\n\n",  MSG16);
  fprintf(fp, "MSG17\n%s\n/MSG\n\n",  MSG17);
  fprintf(fp, "MSG18\n%s\n/MSG\n\n",  MSG18);
  fprintf(fp, "MSG19\n%s\n/MSG\n\n",  MSG19);
  fprintf(fp, "MSG20\n%s\n/MSG\n\n",  MSG20);
  fprintf(fp, "MSG21\n%s\n/MSG\n\n",  MSG21);
  fprintf(fp, "MSG22\n%s\n/MSG\n\n",  MSG22);
  fprintf(fp, "MSG23\n%s\n/MSG\n\n",  MSG23);
  fprintf(fp, "MSG24\n%s\n/MSG\n\n",  MSG24);
  fprintf(fp, "MSG25\n%s\n/MSG\n\n",  MSG25);  
  fprintf(fp, "MSG26\n%s\n/MSG\n\n",  MSG26);
  fprintf(fp, "MSG27\n%s\n/MSG\n\n",  MSG27);  
  
  fclose(fp);
  return 1;
}

/*
 * Load messages
*/
static int
file_readMsg(char *filename)
{
  FILE    *fp;
  char    line[128];
  char    *buff;
  int     msgFlag = 0;
  int     msgNum = 0;
    
  if (!(fp = fopen(filename, "r"))) 
    return -1;
  
  if (!(buff = malloc(1024))){
    fclose(fp);
    return -1;
  }
  
  while( fgets(line, sizeof(line), fp) )
  {
    line[127] = '\0';
    if( line[0] == '#' ) continue;
    
    if( strncmp(line, "MSG", 3) == 0 )
    {
      msgNum = atoi( line+3 ); 
      if( msgNum == 0 )
        syslog(LOG_LOCAL0|LOG_INFO, "MSG number error in %s\n", filename); 
      else 
        msgFlag = 1;
      buff[0] = '\0';
      continue;
    }
    
    if( strncmp(line, "/MSG", 4) == 0 )
    {
      msgFlag = 0;
      msgList[msgNum] = strdup(buff);
      continue;
    }
    
    if( msgFlag )
    {
      if( (strlen(buff) + strlen(line)) < 1024 )
        strcat(buff, line);
      else
        syslog(LOG_LOCAL0|LOG_INFO, "Error, text message > 1023 chars");
    }
    
  }//end while loop
 
  fclose(fp);
  free(buff);
  return 1;
}


int
wiki_redirect(HttpResponse *res, char *location)
{
  char *location_enc = util_httpize(location);
  
  int   header_len = strlen(location_enc) + 14; // ! good idea to check header_len < LIMIT ?
  char *header = alloca(sizeof(char)*header_len); // ! alloca in stack, avoid too large size!

  snprintf(header, header_len, "Location: %s\r\n", location_enc);
  free(location_enc);
  
  http_response_append_header(res, header);
  http_response_printf(res, "<html>\n<p>Redirect to %s</p>\n</html>\n", 
               location);
  http_response_set_status(res, 302, "Moved Temporarily");
  http_response_send(res);

  exit(0);
}

void
wiki_page_forbiden(HttpResponse *res)
{
  http_response_printf(res, msgList[1]);
  http_response_set_status(res, 403, "Forbidden</");
  http_response_send(res);

  exit(0);
}

int
wiki_show_page(HttpResponse *res, char *wikitext, char *page, int autorized)
{
  int private;
  char *html_clean_wikitext = NULL;
  
  //should never occur
  if( wikitext == NULL )
  {
    http_response_printf(res, "internal error %i",__LINE__);
    http_response_send(res);
    return 0;
  }
  
  //if encrypted page and not logged user, page cannot be displayed 
  if ( !strncmp(wikitext,"{{encrypted-01",14) )
  {
    if ( autorized )
    {
      wiki_show_header(res, page, FALSE, autorized);
      if ( !strncmp(wikitext+14,"lock}}",4) )
        http_response_printf(res, SHOWCRYPTFORM, page, wikitext);
      else
        http_response_printf(res, EDITCRYPTFORM, page, wikitext);
      wiki_show_footer(res);
      http_response_send(res);
      return 1;
    }
    else
    {
      wiki_page_forbiden(res);
      return 0;
    }
  }
  // standard page
  http_response_printf_alloc_buffer(res, strlen(wikitext)*2);
  wiki_show_header(res, page, TRUE, autorized);
  html_clean_wikitext = util_htmlize(wikitext, strlen(wikitext));
  private=wiki_print_data_as_html(res, html_clean_wikitext, autorized, page);      
  wiki_show_footer(res);  
  http_response_send(res);
  exit(private);
}

void
wiki_show_edit_page(HttpResponse *res, char *wikitext, char *page,
                    int preview, int autorized)
{
  if (wikitext == NULL) wikitext = "";
  else if ( !strncmp(wikitext,"{{encrypted-01}}",16) ) {
   return;
  }

  wiki_show_header(res, page, FALSE, autorized);
  http_response_printf(res, "%s", ShortHelp);
  
  http_response_printf(res, EditForm, page, wikitext);

  if (preview)
  {
    char *html_clean_wikitext;

    http_response_printf(res, EDITPREVIEW);
    http_response_printf_alloc_buffer(res, strlen(wikitext)*2);

    html_clean_wikitext = util_htmlize(wikitext, strlen(wikitext));

    wiki_print_data_as_html(res, html_clean_wikitext, autorized, page);
  }

  wiki_show_footer(res);

  http_response_send(res);
  exit(0);
}

void
wiki_show_edit_cryptedpage(HttpResponse *res, char *wikitext, char *page,
                    int preview, int autorized)
{
  if (wikitext == NULL) wikitext = "";
  else if ( !strncmp(wikitext,"{{encrypted-01}}",16) ) {
   return;
  }

  wiki_show_header(res, page, FALSE, autorized);

  http_response_printf(res, CREATECRYPTFORM, page, wikitext);
  wiki_show_footer(res);

  http_response_send(res);
  exit(0);
}


void
wiki_show_delete_confirm_page(HttpResponse *res, char *page)
{
  wiki_show_header(res, "Delete Page", FALSE, 0);

  http_response_printf(res, DeleteForm, page, page);

  wiki_show_footer(res);

  http_response_send(res);

  exit(0);
}

void
wiki_show_create_page(HttpResponse *res)
{
  wiki_show_header(res, "Create New Page", FALSE, 0);
  http_response_printf(res, "%s", CreateForm);
  wiki_show_footer(res);

  http_response_send(res);
  exit(0);
}

/* compare files dates */
static int 
changes_compar(const struct dirent **d1, const struct dirent **d2)
{
    struct stat st1, st2;

    stat((*d1)->d_name, &st1);

    stat((*d2)->d_name, &st2);

    if (st1.st_mtime > st2.st_mtime)
      return 1;
    else
      return -1;
}


/* compare files names to sort on first char and length */
static int 
names_compar(const struct dirent **d1, const struct dirent **d2)
{
  if ( tolower(((*d1)->d_name)[0]) ==  tolower(((*d2)->d_name)[0]) )
  {
    if ( strlen((*d1)->d_name) < strlen((*d2)->d_name) ) 
      return 1;
    else
      return -1;
  }

  if ( tolower(((*d1)->d_name)[0]) <  tolower(((*d2)->d_name)[0]) )
    return 1;
  else
    return -1;
}


WikiPageList**
wiki_get_pages(int  *n_pages, char *expr, int exprInName)
/* search expr in each pages or expr==filename; 
 * if exprInName==1 seach expr inside filename */
{
  WikiPageList  **pages;
  struct dirent **namelist;
  int             n, i = 0;
  struct stat     st;
  struct passwd  *pwd;
  struct group   *grp;

  n = scandir(".", &namelist, 0, (void *)changes_compar);
 
  pages = malloc((sizeof(WikiPageList*)+1)*n);

  while(n--) 
  {
    if ((namelist[n]->d_name)[0] == '.' 
    || !strcmp(namelist[n]->d_name, "styles.css"))
      goto cleanup;

    /* are we looking for an expression in the wiki? */
    if (expr != NULL) 
    { 
      if ( !(exprInName && (strcasestr(namelist[n]->d_name, expr))) )
      /* if <<expr>> is not in the filename */
      {                
        /* Super Simple Search inside each pages */
        char *data = NULL;
        /* load the page */
        if ((data = file_read(namelist[n]->d_name)) != NULL)
          if (strcasestr(data, expr) == NULL) //if expr not found in page
            if (strcmp(namelist[n]->d_name, expr) != 0) //if expr doesn't match filename
              goto cleanup;
        }
    }

    stat(namelist[n]->d_name, &st);

    /* ignore anything but regular readable files */
    if (S_ISREG(st.st_mode) && access(namelist[n]->d_name, R_OK) == 0)
    {
      pwd=getpwuid(st.st_uid);
      grp=getgrgid(st.st_gid);
        
      pages[i]        = malloc(sizeof(WikiPageList)+1);
      pages[i]->name  = strdup(namelist[n]->d_name);
      pages[i]->mtime = st.st_mtime;
      if (pwd)
        pages[i]->user_name =  strdup(pwd->pw_name);
      else
        pages[i]->user_name =  strdup("ERR pwd");
      if (grp)
        pages[i]->grp_name =  strdup(grp->gr_name);
      else
        pages[i]->grp_name =  strdup("ERR grp");

      i++;
    }

    cleanup:
      free(namelist[n]);
  } //end while

  *n_pages = i;

  free(namelist);
 
  if (i==0) return NULL;

  return pages;
}

void
wiki_show_secureLogin_page(HttpResponse *res)
{
  //wiki_show_header(res, "Login Page", FALSE, 0);
  if( secureKey )
    http_response_printf(res, "%s", SECURELOGIN2);
  else
    http_response_printf(res, "%s", SECURELOGIN);
  //wiki_show_footer(res);
  http_response_send(res);
  exit(0);
}

void
wiki_show_login_page(HttpResponse *res)
{
  wiki_show_header(res, "Login Page", FALSE, 0);
  if (loginform == 2)
	http_response_printf(res, "%s", LogInForm2);
  else
  	http_response_printf(res, "%s", LogInForm);
  wiki_show_footer(res);

  http_response_send(res);
  exit(0);
}

void
wiki_show_newaccount_page(HttpResponse *res)
{
  wiki_show_header(res, "Login Page", FALSE, 0);
  http_response_printf(res, "%s", NewLogInForm);
  wiki_show_footer(res);

  http_response_send(res);
  exit(0);
}

void
wiki_show_loginfo_page(HttpResponse *res, char *ipsrc)
{
  wiki_show_header(res, "Log Info Page", FALSE, 0);
  
  http_response_printf(res, LogInfo, ipsrc, wikilogin_username(ipsrc));
  wiki_show_footer(res);

  http_response_send(res);
  exit(0);
}


void
wiki_show_index_page(HttpResponse *res, char *dir, int namesort, int autorized)
/* when "Index" clicked : List pages and files inside .Ciwiki */
{
  struct dirent **namelist;
  int     n;
  int     count_files;
  int     numvar;
  
  count_files=4; //4 lines images,files,html,wiki
  numvar=1;
  if (!dir) 
    dir=strdup(".");
  //wiki , file, images. html, templates folders are allowed
  if ( *dir=='.' || !strcmp(dir,"files") || !strcmp(dir,"images") || !strcmp(dir,"html") )
  {
      wiki_show_header(res, "Index", FALSE, 0);

      if( namesort ) {
        //sort name in alphabetic order
        n = scandir(dir, &namelist, 0, (void *)names_compar);
        // link to sort by date
        http_response_printf(res,"<li><a href='Index' title='List all pages in the wiki by dates.'>[ 1/12...31/12 ]</a></a></li>\n");
      }
      else {
        // sort by date change
        n = scandir(dir, &namelist, 0, (void *)changes_compar);
        // link to sort by name
        http_response_printf(res,"<li><a href='Index2' title='List all pages in the wiki by names.'>[ a,b,c,d,e... ]</a></a></li>\n");
      }

      /*prepare an collapsible box. javascript must be enabled! */
      http_response_printf(res, "<div id=""wrapper""><p><a onclick=""expandcollapse('myvar%i');"" title=""Expand or collapse"">Index %i</a></p><div id=""myvar%i"">\n",numvar,numvar,numvar);  
      http_response_printf(res, "<ul>\n");
      //create links to the folders for logged user
      if ( autorized )
      { 
        if( (indexShowWhat & 1) ) //show link to folder images
        {
          if ( !strcmp(dir,PICSFOLDER) )
            http_response_printf(res, "<li><b><a href='Index?Folder=%s'>Folder:%s</a></b></li>\n", PICSFOLDER,PICSFOLDER); 
          else  
            http_response_printf(res, "<li><i><a href='Index?Folder=%s'>Folder:%s</a></i></li>\n", PICSFOLDER,PICSFOLDER); 
        }
        
        if( (indexShowWhat & 2) ) //show link to folder files
        {
          if ( !strcmp(dir,FILESFOLDER) )  
            http_response_printf(res, "<li><b><a href='Index?Folder=%s'>Folder:%s</a></b></li>\n", FILESFOLDER,FILESFOLDER); 
          else
            http_response_printf(res, "<li><i><a href='Index?Folder=%s'>Folder:%s</a></i></li>\n", FILESFOLDER,FILESFOLDER); 
        }
        
        if( (indexShowWhat & 4) ) //show link to folder html
        {
          if ( !strcmp(dir,HTMLFOLDER) )
            http_response_printf(res, "<li><b><a href='Index?Folder=%s'>Folder:%s</a></b></li>\n", HTMLFOLDER,HTMLFOLDER); 
          else
            http_response_printf(res, "<li><i><a href='Index?Folder=%s'>Folder:%s</a></i></li>\n", HTMLFOLDER,HTMLFOLDER); 
        }
        
        if( indexShowWhat ) //show link to folder wiki
        {
          if (*dir=='.')
            http_response_printf(res, "<li><b><a href='Index?Folder=%s'>Folder:%s</a></b></li>\n", ".","Wiki"); 
          else
            http_response_printf(res, "<li><i><a href='Index?Folder=%s'>Folder:%s</a></i></li>\n", ".","Wiki"); 
        }
      }
        
      //links to the files inside the selected folder
      while(n--)
      {
        if ( namelist[n]->d_type == DT_REG )
        {
          //exclude hidden and style
          if ((namelist[n]->d_name)[0] == '.'
              || !strcmp(namelist[n]->d_name, "styles.css"))
            goto cleanup;
          // if exclude templates
          if( !(indexShowWhat & 8) && strstr(namelist[n]->d_name, ".template") )
            goto cleanup;

          //print link to page and page name (previous pages are not printed)
          if ( !strstr(namelist[n]->d_name,".prev.") ) {
            //box is full so create a new one
            if (count_files >=lgindex) {
                count_files=0;
                http_response_printf(res, "</ul>\n");
                http_response_printf(res, "</div></div>\n");
                if (numvar%4 == 0) http_response_printf(res, "<BR>\n");
                numvar++;
                //Note= javascript must be enabled!
                http_response_printf(res, "<div id=""wrapper""><p><a onclick=""expandcollapse('myvar%i');"" title=""Expand or collapse"">Index %i</a></p><div id=""myvar%i"">\n",numvar,numvar,numvar);           
                http_response_printf(res, "<ul>\n");
            }
            /* show filename - link to /folder/filname */
            http_response_printf(res, "<li><a href='%s/%s'>%s</a></li>\n", dir,namelist[n]->d_name, namelist[n]->d_name); 
            count_files++;
          }
            
          cleanup:
          free(namelist[n]);
        }
      } //end while
      http_response_printf(res, "</div></div>\n");
      http_response_printf(res, "</ul>\n");
      free(namelist);
  }
  else
    http_response_printf(res, "Wrong folder.<BR><BR>\n");
    
  wiki_show_footer(res);
  http_response_send(res);
  exit(0);
}

void
wiki_show_search_results_page(HttpResponse *res, char *expr)
/* When search box + return pressed */
{
  WikiPageList **pages = NULL;
  int            n_pages, i;
  int            searchInName, searchInPage, linkFound=0;

  if ( expr == NULL || strlen(expr) == 0 || 
      (strlen(expr) == 1 && (expr[0] == '@' || expr[0] == '/'))
     )
  {
    wiki_show_header(res, "Search", FALSE, 0);
    http_response_printf(res, "No Search Terms supplied");
    wiki_show_footer(res);
    http_response_send(res);
    exit(0);
  }

  searchInName = searchInPage = 1;
  if ( expr[0] == '@' ) { 
    searchInName = 0;
    expr++;
  }
  if ( expr[0] == '/' ) {
    searchInPage = 0;
    expr++;
  }
  
  /* search for exp in the wiki */
  pages = wiki_get_pages(&n_pages, expr, searchInName);
 
  /* if only one page is found, redirect to it */
  if (n_pages == 1) 
    wiki_redirect(res, pages[0]->name);
  
  if (pages)
  {
    /* redirect on page name if exact match */
    /*
    if ( searchInName )
    {
      for (i=0; i<n_pages; i++)
        if ( !strcmp(pages[i]->name, expr) && 
             (strlen(pages[i]->name) == strlen(expr)) )
          wiki_redirect(res, pages[i]->name);
    }
    */
    
    wiki_show_header(res, "Search", FALSE, 0);    

    /* list filename (name of wikipage) containing <<expr>>  but skip .prev.1 */
    if ( searchInName )
    {
      linkFound=0;
      for (i=0; i<n_pages; i++)
        if ( !strstr(pages[i]->name, ".prev.1") && 
              strcasestr(pages[i]->name, expr))
        {
          linkFound++;
          http_response_printf(res, "<a href='%s'>/%s</a><br />\n", 
             pages[i]->name, 
             pages[i]->name);
        }
      if ( linkFound )
        http_response_printf(res, "<br>\n");
      else
        http_response_printf(res, "(No file name match.)<br>\n");
    }
    
    /* list pages containing <<expr>> but skip .prev.1 */
    if ( searchInPage )
    {
      linkFound=0;
      for (i=0; i<n_pages; i++)
        if ( !strstr(pages[i]->name, ".prev.1") )
        {
          linkFound++;
          http_response_printf(res, "<a href='%s'>%s</a><br />\n", 
                     pages[i]->name, 
                     pages[i]->name);
        }

      if ( !linkFound )
        http_response_printf(res, "(Expression not found inside pages.)<br>\n");
    }

  }
  else 
  {
    wiki_show_header(res, "Search", FALSE, 0);
    http_response_printf(res, "No matches!");
  }

  wiki_show_footer(res);
  http_response_send(res);

  exit(0);
}

void 
wiki_show_template(HttpResponse *res, char *template_data)
{
  /* 4 templates - header.html, footer.html, 
                   header-noedit.html, footer-noedit.html

     Vars;

     $title      - page title. 
     $include()  - ?
     $pages 

  */

}

/*
 Contain javascript! Can be an issue if users didn't enabled script exec
*/
void
wiki_show_header(HttpResponse *res, char *page_title, int want_edit, int autorized)
{
  http_response_printf(res, 
    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
    "<html xmlns='http://www.w3.org/1999/xhtml'>\n"
    "<head>\n"
    "<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />\n" 
    "<link rel='SHORTCUT ICON' href='favicon.ico' />\n"
    "<link media='all' href='styles.css' rel='stylesheet' type='text/css' />\n"
    "<title>%s</title>\n"
    "<script type=\"text/javascript\">\n"
    "<!--\n"
    "function expandcollapse(obj) {\n"
    "var el = document.getElementById(obj);\n"
    "if ( el.style.display != \"none\" ) {\n"
		"el.style.display = 'none';\n"
    "}\n"
    "else {\n"
		"el.style.display = '';\n"
    "}\n"
    "}\n"
    "//-->\n"
    "</script>\n"
    "</head>\n"
    "<body>\n", page_title
    );
  
  if (want_edit)
    http_response_printf(res, EditHeader, page_title, page_title, 
                      page_title, autorized ? "You are logged in":"login");
  else
    http_response_printf(res, PageHeader, page_title, "" );
}

void
wiki_show_footer(HttpResponse *res)
{
  http_response_printf(res, "%s", PAGEFOOTER);

  http_response_printf(res, 
     "</body>\n"
     "</html>\n"
     );
}


/* 2014/09/04 : Thanks to Alexander Izmallow for its patch
 * fix ciwiki vulnerability
 */ 
int page_name_is_good(char* page_name)
{
/* We should give access only to subdirs of ciwiki root.
   I guess that check for absense of '/' is enough.

   TODO: Use realpath()
*/
    if (!page_name)
        return FALSE;

    if (!isalnum(page_name[0]))
        return FALSE;

    if (strstr(page_name, ".."))
        return FALSE;

    return TRUE;
}

void
wiki_handle_rest_call(HttpRequest  *req, 
              HttpResponse *res,
              char         *func)
{
  if (func != NULL && *func != '\0')
  {
    if (!strcmp(func, "page/get"))
    {
      char *page = http_request_param_get(req, "page");

      if (page == NULL)
        page = http_request_get_query_string(req);

      if (page && page_name_is_good(page) && (access(page, R_OK) == 0))
      {
        http_response_printf(res, "%s", file_read(page));
        http_response_send(res);
        return;
      }  
    }
    else if (!strcmp(func, "page/set"))
    {
      char *wikitext = NULL, *page = NULL;
      if( ( (wikitext = http_request_param_get(req, "text")) != NULL)
          && ( (page = http_request_param_get(req, "page")) != NULL))
      {
	    if (page_name_is_good(page))
        {
           file_write(page, wikitext);
           /* log modified page name and IP address */
           syslog(LOG_LOCAL0|LOG_INFO, "page %s modified from %s", page ,http_request_get_ip_src(req));
           http_response_printf(res, "success");
        }
        else 
        {
			http_response_printf(res, "error");
		}
        http_response_send(res);
        return;
      }
    }
    else if (!strcmp(func, "page/delete"))
    {
      char *page = http_request_param_get(req, "page");

      if (page == NULL)
        page = http_request_get_query_string(req);

      if (page && page_name_is_good(page) && (unlink(page) > 0))
      {
        http_response_printf(res, "success");
        http_response_send(res);
        return;  
      }
    }
    else if (!strcmp(func, "page/exists"))
    {
      char *page = http_request_param_get(req, "page");

      if (page == NULL)
        page = http_request_get_query_string(req);

      if (page && page_name_is_good(page) && (access(page, R_OK) == 0))
        {
          http_response_printf(res, "success");
          http_response_send(res);
          return;  
        }
    }
    else if (!strcmp(func, "pages") || !strcmp(func, "search"))
    {
      WikiPageList **pages = NULL;
      int            n_pages, i;
      char          *expr = http_request_param_get(req, "expr");

      if (expr == NULL)
        expr = http_request_get_query_string(req);
      
      pages = wiki_get_pages(&n_pages, expr, 0);

      if (pages)
      {
        for (i=0; i<n_pages; i++)
        {
          struct tm   *pTm;
          char   datebuf[64];
          
          pTm = localtime(&pages[i]->mtime);
          strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %H:%M", pTm);
          http_response_printf(res, "%s\t%s\n", pages[i]->name, datebuf);
        }

        http_response_send(res);
        return;  
      }
    }
  }

  http_response_set_status(res, 500, "Error");
  http_response_printf(res, "<html><body>Failed</body></html>\n");
  http_response_send(res);

  return;  
}
/////////////////////////////////////////////////////////////////////
/* wiki_handle_http_request is the Main function
 * It gets the request and then calls the functions to:
 *  - load page (wikitext)
 *  - convert wikitext to html
 *  - edit wikitext 
 *  - save, delete wikitext
 *  - list pages (index)
 *  - list changes
 *  - login 
 *  - get permission with wikilogin_getpermission(client ip)
 */
void
wiki_handle_http_request(HttpRequest *req)
{
  HttpResponse *res      = http_response_new(req);
  char         *page     = http_request_get_path_info(req); 
  char         *command  = http_request_get_query_string(req); 
  char         *wikitext = NULL;
  int          return_code=0, private=1, autorized=0;
  char         *msg,*link;
  char         *listbox;
  char         *value;
  char         *str_ptr;
  char         *folder;
  char         *username;
  char         *password;

  util_dehttpize(page);// remove any encoding on the requested page name.
  
  /* If login is required before any request and if user is already not logged */
  if ( secureLogin && !wikilogin_getpermission(http_request_get_ip_src(req)) )
  {
    if ( http_request_param_get(req, "username") != NULL )
    {
      if( secureKey )
      {
        username = decode(secureKey, http_request_param_get(req, "cypunm"));
        password = decode(secureKey, http_request_param_get(req, "cyppsw"));
      }
      else
      {
        username = http_request_param_get(req, "username");
        password = http_request_param_get(req, "password");
      }
/*
      //only to debug
      fprintf(stderr,"(%s){%s}[%s]", 
              secureKey,
              username, 
              password); //to delete!
*/
      
      /* log is valid ? */
      if ( (return_code=wikilogin_isvalid(
            username, password,
            "","","",
            http_request_get_ip_src(req) ) ) > 0 )
      {
        /* code > 0, so permission is granted */
        wikilogin_setpermission(
          http_request_get_ip_src(req), username );
        /* store in log file */
        syslog(LOG_LOCAL0|LOG_INFO, "Login successful from %s",
              http_request_get_ip_src(req));
        /* go the the home page */
        page="/WikiHome";
        wiki_redirect(res, "WikiHome");
      }
      else 
      {
        // wrong login!!!
        http_response_set_status(res, 404, "Not Found");
        http_response_printf(res, "<html><body>Login error. Access denied.</body></html>\n");
        http_response_send(res);
      }
    }
    else
      // provide the login page
      wiki_show_secureLogin_page( res );

    exit(0); 
  }

  if (!strcmp(page, "/"))
  {
    if (access("WikiHome", R_OK) != 0)
      wiki_redirect(res, "/WikiHome?create");
    page = "/WikiHome";
  }

  if (!strcmp(page, "/styles.css"))
  {
    /*  Return CSS page */
    http_response_set_content_type(res, "text/css");
    http_response_printf(res, "%s", CssData);
    http_response_send(res);
    exit(0);
  }
  
  if (!strcmp(page, "/favicon.ico"))
  {
    /*  Return favicon */
    http_response_set_content_type(res, "image/ico");
    http_response_set_data(res, FaviconData, FaviconDataLen); 
    http_response_send(res);
    exit(0);
  }

  /* filter file extensions */
  if ( (str_ptr=strrchr(page, '.')) ) 
  {
    /* check if it's an image extension */
    if ( !strcasecmp(str_ptr, ".png") || !strcasecmp(str_ptr, ".jpeg") ||
         !strcasecmp(str_ptr, ".jpg") || !strcasecmp(str_ptr, ".gif") ||
         !strcasecmp(str_ptr, ".pdf") )
    {
      http_response_send_smallfile(res, page+1, "image/ico", MAXFILESIZE); //size limitation, see ci.h
      exit(0);
    }
    /* to download any file located in the folder /files/  */
    else if (strstr(page, "/files/"))
    {
      http_response_send_bigfile(res, page+1, "application/octet-stream");
      exit(0);
    }
    /* html, css and js are allowed in the folder /html/ */
    else if ( !strncmp(page, "/html/",6) )
    {
      /* check if it's html file */
      if ( !strcasecmp(str_ptr, ".htm") || !strcasecmp(str_ptr, ".html") )
      {
        /*  Return html page - Need to be tested to be sure there no safety issue! */
        http_response_send_bigfile(res, page+1, "text/html"); // => no size limitation
        //http_response_send_smallfile(res, page+1, "html", MAXFILESIZE); //size limitation, see ci.h
        exit(0);
      }
      /* check if it's css file */
      else if ( !strcasecmp(str_ptr, ".css") )
      {
        /*  Return css page - Need to be tested to be sure there no safety issue! */
        http_response_send_bigfile(res, page+1, "text/css"); // => no size limitation
        //http_response_send_smallfile(res, page+1, "html", MAXFILESIZE); //size limitation, see ci.h
        exit(0);
      }
      /* check if it's js file */
      else if ( !strcasecmp(str_ptr, ".js") )
      {
        /*  Return js code - Need to be tested to be sure there no safety issue! */
        http_response_send_bigfile(res, page+1, "application/javascript"); // => no size limitation
        //http_response_send_smallfile(res, page+1, "html", MAXFILESIZE); //size limitation, see ci.h
        exit(0);
      }
      
    } 
    //Next todo: Allow css and javascript files located in the folder/html/
  }
  
  page = page + 1;      /* skip slash */

  if (!strncmp(page, "api/", 4))
  {
    char *p;

    page += 4; 
    for (p=page; *p != '\0'; p++)
      if (*p=='?') { *p ='\0'; break; }
    
    wiki_handle_rest_call(req, res, page); 
    exit(0);
  }

  /* A little safety issue a malformed request for any paths,
   * There shouldn't need to be any..
   */
  if (strchr(page, '/'))
  {
    http_response_set_status(res, 404, "Not Found");
    http_response_printf(res, "<html><body>404 Not Found</body></html>\n");
    http_response_send(res);
    exit(0);
  }

  /* Safety issue if Exec_allowed. login required! */
  if (Exec_allowed && !strcmp(page, ".Execute") 
      && wikilogin_getpermission(http_request_get_ip_src(req)) ) 
  {  
    FILE *pop;
    int status;
    char string[256];
    
    string[255]='\0';
    status=0;
    //char* scriptname;
    char* scriptfullpath;

    /* exec file located in /scripts/ */
    asprintf(&scriptfullpath,"./scripts/%s",http_request_param_get(req, "Script"));
    if ( (pop = popen(scriptfullpath, "w")) )
    {
      while (fgets(string, 255, pop) != NULL)
      {
        if (*string=='\0' || *string==EOF) break;
        http_response_printf(res, "%s\n",string);
        *string='\0';
      }
      status = pclose(pop);
      if (status==-1) 
        http_response_printf(res, "\n%s\n","Error executing script!");
    }
    else
      http_response_printf(res, 
        "<html><body><strong>Cannot run script!</strong></body></html>\n");

    http_response_send(res);

    exit(0);
  }
  else if (Upload_allowed && !strcmp(page, "Upload")
           && wikilogin_getpermission(http_request_get_ip_src(req)) ) 
  {
    if (upload_status < -1)
        msg=strdup(msgList[2]);
    else if (upload_status == -1)    
        msg=strdup(msgList[3]);
    else    
        asprintf(&msg,msgList[4],upload_status);
        
    http_response_printf(res, "<html><body><strong>%s</strong><br><br>"
                                    "<a %s</a>"
                                    "</body></html>\n",msg,BACK);
    http_response_send(res);
    
    //upload_status=0;
    
    exit(0);        
  }
  else if (!strcmp(page, "Login"))
  {
    if ( !strncmp(command, "rac=",4) )
    /* url: /Login?rac=rac=xxxxxxxxx&username
     * rac means return of access code */
    {
      char *username=NULL;
      if ( (username=wikirac_isvalid( 
            command+4, 
            http_request_get_ip_src(req))) )
      {
        /* code > 0, so permission is granted */
        wikilogin_setpermission(
          http_request_get_ip_src(req),
          username );
        /* store in log file */
        syslog(LOG_LOCAL0|LOG_INFO, "Login successful from %s",
              http_request_get_ip_src(req));
        /* go the the home page */
        page="/WikiHome";
        wiki_redirect(res, "WikiHome");
      }
      else
      {
        /* Failure: Return a msg to the user */
        msg=strdup(msgList[5]);
        link=strdup("href='WikiHome'>Home Page");
        http_response_printf(res, "<html><body><strong>%s</strong><br><br>"
                                  "<a %s</a>"
                                  "</body></html>\n",msg,link);
        http_response_send(res);
        /* store msg in log file */
        syslog(LOG_LOCAL0|LOG_INFO, "Login error %s from %s",
              msg ,http_request_get_ip_src(req));
        free(msg);
        exit(0);        
      }
    }
    else if ( http_request_param_get(req, "logoff") != NULL )
    /* the form contains the input name:logoff. */
    {
      wikilogin_logoff(http_request_get_ip_src(req));
      /* go the the home page */
      page="/WikiHome";
      wiki_redirect(res, "WikiHome");
      exit(0); 
    }
    else if ( http_request_param_get(req, "chgpwd") != NULL )
    /* the form contains the input name:chgpwd. */
    {
      if ( wikilogin_username(http_request_get_ip_src(req)) != NULL ) 
      {  
        int status = wikilogin_chgpwd(
          http_request_get_ip_src(req),
          http_request_param_get(req, "password"),
          http_request_param_get(req, "newpassword") );
          
        if (status > 0)
        {    
          /* store in log file */
          syslog(LOG_LOCAL0|LOG_INFO, "PWD change from %s status:%i",
              http_request_get_ip_src(req), status);    
              
          /* Confirm and go the the home page */
          msg=strdup(msgList[6]);
          link=strdup("href='WikiHome'>Home Page");
          http_response_printf(res, "<html><body><strong>%s</strong><br><br>"
                                    "<a %s</a>"
                                    "</body></html>\n",msg,link);
          http_response_send(res);
          /* store msg in log file */
          syslog(LOG_LOCAL0|LOG_INFO, "Password changed from %s",
			http_request_get_ip_src(req));
          free(msg);
          exit(0); 
	    } 
	    else
	    {
		  /* Failure: Return a msg to the user */    
          switch(status) {  
		  case -1  : 
            msg=strdup(msgList[7]);
            link=strdup(BACK);
            break;       
          case -2  : 
            msg=strdup(msgList[8]);
            link=strdup(BACK);
            break;  
          case -3  : 
            msg=strdup(msgList[9]);
            link=strdup(BACK);
            break; 	
          case -10 : 
            msg=strdup(msgList[10]);
            link=strdup(BACK);
            break;       
          case -20 : 
            msg=strdup(msgList[11]);
            link=strdup(BACK);
            break;       
          case -100: 
            msg=strdup(msgList[12]);
            link=strdup("href='WikiHome'>Home Page");
            break;              
          default : 
            msg=strdup(msgList[13]);
            link=strdup("href='WikiHome'>Home Page");
          }
            
          http_response_printf(res, "<html><body><strong>%s</strong><br><br>"
                                    "<a %s</a>"
                                    "</body></html>\n",msg,link);
          http_response_send(res);
          /* store msg in log file */
          syslog(LOG_LOCAL0|LOG_INFO, "Change password error %s from %s",
              msg ,http_request_get_ip_src(req));
          free(msg);
          exit(0); 
	    }
      }
      else
      {
       /* Failure: Return a msg to the user */   
        msg=strdup(msgList[14]);
        link=strdup("href='WikiHome'>Home Page");
        http_response_printf(res, "<html><body><strong>%s</strong><br><br>"
                                  "<a %s</a>"
                                  "</body></html>\n",msg,link);
        http_response_send(res);
        free(msg);
        exit(0);       
      }
    }
    else if ( http_request_param_get(req, "username") != NULL )
     /* the form contains an username, it's a login page */
    {
      /* log is valid ? */
      if ( (return_code=wikilogin_isvalid(
            http_request_param_get(req, "username"),
            http_request_param_get(req, "password"),
            http_request_param_get(req, "email"),
            http_request_param_get(req, "code"),
            http_request_param_get(req, "newaccount"),
            http_request_get_ip_src(req) ) ) > 0 )
      {
        /* code > 0, so permission is granted */
        wikilogin_setpermission(
          http_request_get_ip_src(req),
          http_request_param_get(req, "username") );
        /* store in log file */
        syslog(LOG_LOCAL0|LOG_INFO, "Login successful from %s",
              http_request_get_ip_src(req));
        /* go the the home page */
        page="/WikiHome";
        wiki_redirect(res, "WikiHome");
      }
      else
      /* code < 1 reports error */
      {
        switch(return_code) {
        case 0  : 
          msg=strdup(msgList[15]);
          link=strdup("href='WikiHome'>Home Page");
          break;
        case -1  : 
          msg=strdup(msgList[16]);
          link=strdup(BACK);
          break;       
        case -2  : 
          msg=strdup(msgList[17]);
          link=strdup(BACK);
          break;  
        case -3  : 
          msg=strdup(msgList[18]);
          link=strdup(BACK);
          break;         
        case -10 : 
          msg=strdup(msgList[19]);
          link=strdup(BACK);
          break;
        case -12 :
          msg=strdup(msgList[20]);
          link=strdup(BACK);
          break;          
        case -20 : 
          msg=strdup(msgList[21]);
          link=strdup(BACK);
          break;       
        case -30 : 
          msg=strdup(msgList[22]);
          link=strdup(BACK);
          break;
        case -35 : 
          msg=strdup(msgList[23]);
          link=strdup(BACK);
          break;  
        case -40 : 
          msg=strdup(msgList[24]);
          link=strdup("href='WikiHome'>Home Page");
          break;  
        case -100: 
          msg=strdup(msgList[25]);
          link=strdup("href='WikiHome'>Home Page");
          break;              
        default : 
          msg=strdup(msgList[26]);
          link=strdup("href='WikiHome'>Home Page");
        }
        /* Return a msg to the user */
        http_response_printf(res, "<html><body><strong>%s</strong><br><br>"
                                  "<a %s</a><br></body></html>\n",msg,link);
        http_response_send(res);
        /* store msg in log file */
        syslog(LOG_LOCAL0|LOG_INFO, "Login error %s from %s",
              msg ,http_request_get_ip_src(req));
        free(msg);
        exit(0);        
      }
    }
    else
    /* will serve a page */
    {
      char *ipsrc = strdup(http_request_get_ip_src(req));
      if ( wikilogin_getpermission( ipsrc ) )
        /* serve the logoff & chg pwd page */
        wiki_show_loginfo_page( res, ipsrc );
      else
        /* serve the login page */
        wiki_show_login_page( res );
    }
  }
  else if (!strcmp(page, "NewAccount"))
  {
    /* serve the login page */
    wiki_show_newaccount_page(res);
  }
  else if (!strcmp(page, "Changes"))
  {
	//grant permission to show changes (to protect {privacy}} data)
    if ( (autorized=wikilogin_getpermission(http_request_get_ip_src(req))) )
    {
      if ( (page = http_request_param_get(req, "diff1")) )
        wiki_show_diff_between_pages(res, page, 1);
      else if ( (page = http_request_param_get(req, "diff2")) )
        wiki_show_diff_between_pages(res, page, 2);  
      else
        wiki_show_changes_page(res);
      autorized=0; //return to a secure mode
    }
    else
        wiki_page_forbiden(res); //err msg and exit
  }
  else if (!strcmp(page, "ChangesRss"))
  {
    wiki_show_changes_page_rss(res);
  }
  else if (!strncmp(page, "Index", 5))
  {
    int namesort = 0;
    if( *(page+5) == '2' ) namesort = 1; //Index2 : sort by name else default is date
    autorized=wikilogin_getpermission(http_request_get_ip_src(req)); //get permission to show html, image,file
    if ( (folder=http_request_param_get(req, "Folder")) )
      wiki_show_index_page(res,folder,namesort,autorized);
    else
      wiki_show_index_page(res,".",namesort,autorized);
  }
  else if (!strcmp(page, "Search"))
  {
    wiki_show_search_results_page(res, http_request_param_get(req, "expr"));
  }
  else if (!strcmp(page, "Create"))
  /* unlogged user cannot create a new page!
   * Create a new page from an empty form
   * or creat a new page from a template.
   * If a selected template doesn't exit, it will be created. 
  */
  {
    /* check permission to create a page */  
    if ( (autorized=wikilogin_getpermission(http_request_get_ip_src(req))) )
    {
      /* check the name of the page */
      if ( (page=http_request_param_get(req, "title")) != NULL && 
           page_name_is_good(page) )
      {
        /* check if encrypt text*/
        if ( (http_request_param_get(req, "encrypt")) != NULL
            && strcmp(http_request_param_get(req, "encrypt"),"yes") == 0 )
        {
          wiki_show_edit_cryptedpage(res, wikitext, page, FALSE, autorized);
        }
        /* check if a template is selected */  
        else if ( (http_request_param_get(req, "template")) != NULL
            && strcmp(http_request_param_get(req, "template"),"none") != 0 )
        {
          /* check the template exist */    
          if (access(http_request_param_get(req, "template"), R_OK) == 0 )
          {    
            /* check the page doesn't exist yet */    
            if (access(page, R_OK) != 0 )
            {  
              /* create page from template */
              wikitext = file_read(http_request_param_get(req, "template"));
              page=http_request_param_get(req, "title");
              wiki_show_edit_page(res, wikitext, page, FALSE, autorized);
            }
            else
            {
              /* Inform the user that the page exists*/
              http_response_printf(res, "<html><body><strong>%s</strong><br><br>"
              "<a %s</a><br></body></html>\n", msgList[27],
              "href='javascript:javascript:history.go(-1)'>Return to the previous page.");
              http_response_send(res);
              exit(0);        
            }
          }
          else
          {
             /* template selected doesn't exit - Create the template and redirect */
             wiki_redirect(res, http_request_param_get(req, "template"));
          }
        }
        else
        {
        /* No template selected - create page and redirect */
        wiki_redirect(res, http_request_param_get(req, "title"));
        }
      }
      else
      {
         /* serve the create page form  */
        wiki_show_create_page(res);
      }
    }
    else
      wiki_page_forbiden(res); //err msg and exit
  } //end create page
  else
  {
    /* grant permission */
    autorized=wikilogin_getpermission(http_request_get_ip_src(req));
      
    if (access(page, R_OK) == 0) 
    /* page exists */
    {
      wikitext = file_read(page);
      /* log read page name and IP address */
      syslog(LOG_LOCAL0|LOG_INFO, "page %s viewed from %s", page, http_request_get_ip_src(req));
    } 
    else private=0; //page doesn't exit yet,so no privacy that allows to save the new page

    /* Add entry for memo with checkbox, small dairy */
    if ( !strcmp(command, "entry") )
    {
      if ( http_request_param_get(req, "add") )
      {
        value = http_request_param_get(req, "datafield"); //need the field of data
        char *newdata = http_request_param_get(req, "data"); //data to add 
        wikitext = wiki_add_entry(page, newdata, value); //insert in the page
        file_write(page, wikitext);
      }
      else if ( http_request_param_get(req, "delete") )
      {
        listbox = http_request_checkbox_get(req);
        wikitext = wiki_delete_entry(page, listbox, 0);
        file_write(page, wikitext);
      }
      else if ( http_request_param_get(req, "OKselect") )
      {
        char *selectValue = http_request_param_get(req, "selectbox");
        
        if ( !strcmp(selectValue, "delete") )
        {
          listbox = http_request_checkbox_get(req);
          wikitext = wiki_delete_entry(page, listbox, 1);
          file_write(page, wikitext);
        }
        else if ( !strcmp(selectValue, "strike") )
        {
          listbox = http_request_checkbox_get(req);
          wikitext = wiki_formating_entry(page, listbox, '-');
          file_write(page, wikitext);
        }
        else if ( !strcmp(selectValue, "bold") )
        {
          listbox = http_request_checkbox_get(req);
          wikitext = wiki_formating_entry(page, listbox, '*');
          file_write(page, wikitext);
        }
        else if ( !strcmp(selectValue, "highlight") )
        {
          listbox = http_request_checkbox_get(req);
          wikitext = wiki_formating_entry(page, listbox, '+');
          file_write(page, wikitext);
        }
        else if ( !strcmp(selectValue, "mark") )
        {
          listbox = http_request_checkbox_get(req);
          wikitext = wiki_formating_entry(page, listbox, '#');
          file_write(page, wikitext);
        }
        else if ( !strcmp(selectValue, "unformat") )
        {
          listbox = http_request_checkbox_get(req);
          wikitext = wiki_unformat_entry(page, listbox);
          file_write(page, wikitext);
        }
      }
    }

    /* Permission is required */
    if ( !strcmp(command, "delete") )
    {
      if (autorized)
      {
        if (http_request_param_get(req, "confirm"))
        {
          unlink(page);
          wiki_redirect(res, "WikiHome");
        }
        else if (http_request_param_get(req, "cancel"))
        {
          wiki_redirect(res, page);
        }
        else
        {
          wiki_show_delete_confirm_page(res, page);
        }
      }
      else
        wiki_page_forbiden(res); //err msg and exit
    }
    /* To edit/create wiki page : Permission can be required */
    else if ( !strcmp(command, "edit") || !strcmp(command, "create") )
    {
      if (autorized || !private)
      {
        char *newtext = http_request_param_get(req, "wikitext");

        if (http_request_param_get(req, "save") && newtext)
        {
          file_write(page, newtext);
          /* log modified page name and IP address */
          syslog(LOG_LOCAL0|LOG_INFO, "page %s modified from %s", page ,http_request_get_ip_src(req));
          wiki_redirect(res, page);
        }
        else if (http_request_param_get(req, "cancel"))
        {
          wiki_redirect(res, page);
        }

        if (http_request_param_get(req, "preview"))
        {
          wiki_show_edit_page(res, newtext, page, TRUE, TRUE);
        }
        else
        {
          wiki_show_edit_page(res, wikitext, page, FALSE, TRUE);
        }
      }
      else
        wiki_page_forbiden(res); //err msg and exit
    }
    /* To edit/create crypted page : Permission can be required */
    else if ( !strcmp(command, "editcrypt") || !strcmp(command, "createcrypt") )
    {
      if (autorized || !private)
      {
        char *newtext = http_request_param_get(req, "wikitext");  //? check wikitext?
      }
      else
        wiki_page_forbiden(res); //err msg and exit
      //crypto  
      wiki_show_edit_cryptedpage(res, wikitext, page, FALSE, TRUE);
    }  
    else 
    /* there's no command : Show the existing page or create it if it doesn't exit  */
    {
      if (wikitext)
      /* page exist, so just show the page */
      { 
        /* private is used to prevent edit/delete */
        private=wiki_show_page(res, wikitext, page, autorized);
      }
      else
      /* page doesn't exist, create it! */
      {
        if ( autorized )
        {
          char buf[1024];
          snprintf(buf, sizeof(buf), "%s?create", page);
          wiki_redirect(res, buf);
        }
        else
          wiki_page_forbiden(res); //err msg and exit
      }
    }
  } 
}

///////////////////////////////////////////////////////////////////////
/* 1st function called only for the startup:
 * -----------------------------------------
 * create the folders, create the help and home pages,
 * erase the previous login granted */
 //////////////////////////////////////////////////////////////////////
int
wiki_init(char *ciwiki_home, unsigned restore_Wiki, unsigned create_htmlHome)
{
  char datadir[512] = { 0 };
  struct stat st;  

  /* look where the pages are/will be located */
  if (ciwiki_home)
  {
    /* datadir was passed as arg in the cmd line */
    snprintf(datadir, 512, "%s", ciwiki_home);
  }
  else 
  {
    if (getenv("CIWIKIHOME"))
    {
      /* datadir is passed in the environment */
      snprintf(datadir, 512, "%s", getenv("CIWIKIHOME"));
    }
    else
    {
      /* default datadir */
      if (getenv("HOME") == NULL)
      {
        fprintf(stderr, "Unable to get home directory, is HOME set?\n");
        exit(1);
      }
      snprintf(datadir, 512, "%s/.ciwiki", getenv("HOME"));
    }
  }
  
  /* Check if datadir exists and create if not */
  if (stat(datadir, &st) != 0 )
  {
    if (mkdir(datadir, 0755) == -1)
    {
      fprintf(stderr, "Unable to create '%s', giving up.\n", datadir);
      exit(1);
    }
  }
  
  /* go to datadir */
  if ( chdir(datadir) ) {
    errorcnt++;
    fprintf(stderr, "Unable to chdir: '%s'\n", datadir);
  }
  
  /* Check if datadir/images exists and create if not */
  if (stat(PICSFOLDER, &st) != 0 )
  {
    if (mkdir(PICSFOLDER, 0755) == -1)
    {
      fprintf(stderr, "Unable to create '%s', giving up.\n",PICSFOLDER);
      exit(1);
    }
  }
  
  /* Check if datadir/permissions exists and create if not */
  if (stat(ACCESSFOLDER, &st) != 0 )
  {
    if (mkdir(ACCESSFOLDER, 0755) == -1)
    {
      fprintf(stderr, "Unable to create '%s', giving up.\n",ACCESSFOLDER);
      exit(1);
    }
  }
  
  /* Check if datadir/configuration exists and create if not */
  if (stat(CONFIGFOLDER, &st) != 0 )
  {
    if (mkdir(CONFIGFOLDER, 0755) == -1)
    {
      fprintf(stderr, "Unable to create '%s', giving up.\n",CONFIGFOLDER);
      exit(1);
    }
  } 
  
  /* Check if datadir/files exists and create if not */
  if (stat(FILESFOLDER, &st) != 0 )
  {
    if (mkdir(FILESFOLDER, 0755) == -1)
    {
      fprintf(stderr, "Unable to create '%s', giving up.\n",FILESFOLDER);
      exit(1);
    }
  }

  /* Check if datadir/html exists and create if not */
  if (stat(HTMLFOLDER, &st) != 0 )
  {
    if (mkdir(HTMLFOLDER, 0755) == -1)
    {
      fprintf(stderr, "Unable to create '%s', giving up.\n",HTMLFOLDER);
      exit(1);
    }
  }

  /* Check if datadir/scripts exists and create if not */
  if (stat(SCRIPTSFOLDER, &st) != 0 )
  {
    if (mkdir(SCRIPTSFOLDER, 0755) == -1)
    {
      fprintf(stderr, "Unable to create '%s', giving up.\n",SCRIPTSFOLDER);
      exit(1);
    }
  }

  /* Write Default Help, Home page and template 01 if they do not exist 
   * or rewrite Default Help or Default Home page */
  if ( access("WikiHelp", R_OK) != 0 || (restore_Wiki & 1) )
    file_write("WikiHelp", HELPTEXT);

  if ( access("WikiHome", R_OK) != 0 || (restore_Wiki & 2) ) 
    file_write("WikiHome", HOMETEXT);
    
  if ( access("01.template", R_OK) != 0 ) 
    file_write("01.template", TEMPLATE01);  
      
  if ( create_htmlHome )
    file_write("WikiHome", HomeRedirect);
    
  /* Write Default styles.css, header, login forms... if they don't exist
   * or rewrite Defaults. */

  if ( access(CONFIGFOLDER"/styles.css", R_OK) != 0 || (restore_Wiki & 4) ) 
    file_write(CONFIGFOLDER"/styles.css", STYLESHEET);
  else
    /* Read in optional CSS data file*/
    CssData = file_read(CONFIGFOLDER"/styles.css");
    
  if ( access(CONFIGFOLDER"/EditHeader.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/EditHeader.htm", EDITHEADER);
  else
    /* Read in optional html data file*/
    EditHeader = file_read(CONFIGFOLDER"/EditHeader.htm");
    
  if ( access(CONFIGFOLDER"/PageHeader.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/PageHeader.htm", PAGEHEADER);
  else
    /* Read in optional html data file*/
    PageHeader = file_read(CONFIGFOLDER"/PageHeader.htm");
    
  if ( access(CONFIGFOLDER"/ShortHelp.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/ShortHelp.htm", SHORTHELP);
  else
    /* Read in optional html data file*/
    ShortHelp = file_read(CONFIGFOLDER"/ShortHelp.htm");   
     
  if ( access(CONFIGFOLDER"/LogInForm.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/LogInForm.htm", LOGINFORM);
  else
    /* Read in optional html data file*/
    LogInForm = file_read(CONFIGFOLDER"/LogInForm.htm");   
    
  if ( access(CONFIGFOLDER"/LogInForm2.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/LogInForm2.htm", LOGINFORM2);
  else
    /* Read in optional html data file*/
    LogInForm2 = file_read(CONFIGFOLDER"/LogInForm2.htm");  
    
  if ( access(CONFIGFOLDER"/NewLogInForm.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/NewLogInForm.htm", NEWLOGINFORM);
  else
    /* Read in optional html data file*/
    NewLogInForm = file_read(CONFIGFOLDER"/NewLogInForm.htm");   
    
  if ( access(CONFIGFOLDER"/LogInfo.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/LogInfo.htm", LOGINFO);
  else
    /* Read in optional html data file*/
    LogInfo = file_read(CONFIGFOLDER"/LogInfo.htm");       
  
  if ( access(CONFIGFOLDER"/CreateForm.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/CreateForm.htm", CREATEFORM);
  else
    /* Read in optional html data file*/
    CreateForm = file_read(CONFIGFOLDER"/CreateForm.htm");  
  
  if ( access(CONFIGFOLDER"/EditForm.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/EditForm.htm", EDITFORM);
  else
    /* Read in optional html data file*/
    EditForm = file_read(CONFIGFOLDER"/EditForm.htm"); 
 
  if ( access(CONFIGFOLDER"/DeleteForm.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/DeleteForm.htm", DELETEFORM);
  else
    /* Read in optional html data file*/
    DeleteForm = file_read(CONFIGFOLDER"/DeleteForm.htm");      

  if ( access(CONFIGFOLDER"/HomeRedirect.htm", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_write(CONFIGFOLDER"/HomeRedirect.htm", HOMEREDIRECT);
  else
    /* Read in optional html data file*/
    HomeRedirect = file_read(CONFIGFOLDER"/HomeRedirect.htm");
    
  if ( access(CONFIGFOLDER"/Messages.txt", R_OK) != 0 || (restore_Wiki & 8) ) 
    file_writeMsg(CONFIGFOLDER"/Messages.txt");
  else
    /* Read in optional html data file*/
    file_readMsg(CONFIGFOLDER"/Messages.txt");

  
  /* use the Favicon as a png picture. */
  if ( access(PICSFOLDER"/ciwiki.png", R_OK ) != 0) {
    FILE* fp;  
    if ( (fp = fopen(PICSFOLDER"/ciwiki.png", "wb")) ) {
      unsigned char *picData = FaviconData;
      int picLen = FaviconDataLen;
      int bytes_written=0;
  
      while ( picLen > 0 )
      {
        bytes_written = fwrite(picData, sizeof(char), picLen, fp);
        picLen = picLen - bytes_written;
        picData = picData + bytes_written;
      }
      fclose(fp);
    }
    else
	  fprintf(stderr, "Unable to create '%s'\n",PICSFOLDER"/ciwiki.png");
  }
  
  /* if favicon.ico file exist then load it 
   else use the default favicon stored at the end of wikitext.h */
  if ( access(".favicon.ico", R_OK ) == 0) 
  {
    FILE*       fp;
    int         len;

    if ( (fp = fopen(".favicon.ico", "rb")) )
    {
      /* get file size */
      fseek (fp , 0 , SEEK_END);
      if ( ftell(fp) < FAVICONDATAMAX )
      { 
        rewind (fp);      
        len = fread(FaviconData, 1,FAVICONDATAMAX, fp);
        if (len >= 0) FaviconData[len] = '\0';
        FaviconDataLen=len;
        fprintf(stderr,"Favicon file is loaded %i bytes\n",len);
      }
      else
        fprintf(stderr,"Favicon file is too large!\n");
      fclose(fp);
    }
    else
      fprintf(stderr,"Favicon file cannot open!\n");
  }	
  else
    fprintf(stderr,"Use internal ciwki favicon.\n");
    
  /* Delete previous permission list */
  remove(ACCESSFOLDER"/.session.txt");
  
  return 1;
}

