#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "global.h"
#include "vpopmail.h"

extern int password_len;
extern char verify, *redirect, *password, allowpassword, advertise;
char *dom = NULL, *user = NULL, *fname = NULL, *cemail = NULL, *pass = NULL,
     *vpass = NULL;

void go_register(void)
{
  int ret = 0;
  char *pword = NULL;

  dom = cgi_is_var("dom");
  fname = cgi_is_var("fname");
  user = cgi_is_var("user");
  cemail = cgi_is_var("cemail");

  if ((!dom) || (!user) || (!fname))
     global_error("Misconfigured templates.", 0, 0);

  if (!allowpassword) {
     if (!cemail)
        global_error("Misconfigured templates.", 0, 0);
  }
  else {
     pass = cgi_is_var("pass");
     vpass = cgi_is_var("vpass");

     if ((!pass) || (!vpass))
        global_error("Misconfigured templates.", 0, 0);
  }

  if (!allowpassword) {
     if (password)
        pword = password;
     else {
        pword = gen_pass(password_len);
        if (pword == NULL) {
           global_warning("Out of resources.");
           global_warning("Please wait, and try again.");

           t_open(T_REGISTER);
        }
     }
  }
  else
     pword = pass;

  global_par("RP", pword);
  global_par("VP", pword);

  ret = fields_okay();

  if (*dom)
     global_par("RD", dom);
  
  if (*user)
     global_par("RU", user);

  if (*fname)
     global_par("RN", fname);

  /*
     Always do this, because cemail can be optional.
  */
  if (cemail)
     global_par("CE", cemail);

  if ((!(*dom)) || (!(*user)) || (!(*fname))) {
     global_warning("Please fill in all fields.");

     if (allowpassword)
        t_open(T_REGISTER_WITH_PASSWORD);
     else
        t_open(T_REGISTER);

     return;
  }

  if (allowpassword) {
     if ((!(*pass)) || (!(*vpass))) {
        global_warning("Please fill in all fields.");
        t_open(T_REGISTER_WITH_PASSWORD);
        return;
     }

     if (strcmp(pass, vpass)) {
        global_warning("Passwords do not match.");
        t_open(T_REGISTER_WITH_PASSWORD);
        return;
     }

     pword = pass;
  }

  /*
     Field checking from above.
  */
  if (!ret) {
     global_warning("Please fill in all fields.");

     if (allowpassword)
        t_open(T_REGISTER_WITH_PASSWORD);
     else
        t_open(T_REGISTER);
  }

  if (!allowpassword) {
     if (!(*cemail)) {
        global_warning("Please fill in all fields.");
        t_open(T_REGISTER);
        return;
     }
  }

  if (strlen(dom) >= 165) {
     global_warning("Invalid domain.");

     if (allowpassword)
        t_open(T_REGISTER_WITH_PASSWORD);
     else
        t_open(T_REGISTER);

     return;
  }

  if (!(is_domain(dom))) {
     global_warning("You may not sign up for that domain.");
     global_warning("Please choose another.");

     if (allowpassword)
        t_open(T_REGISTER_WITH_PASSWORD);
     else
        t_open(T_REGISTER);

     return;
  }

  if (strlen(user) > 20) {
     global_warning("Please supply a shorter username.");

     if (allowpassword)
        t_open(T_REGISTER_WITH_PASSWORD);
     else
        t_open(T_REGISTER);
  }

  ret = add_user(user, dom, pword, fname);

  if (ret != VA_SUCCESS) {
     /*
        This is where we handle the great deal of error
        messages vpopmail might throw back at us.
     */

     if ((ret == VA_BAD_CHAR) || (ret == VA_ILLEGAL_USERNAME)) {
        global_warning("That username is illegal.");
        global_warning("Please select another.");
        t_open(T_REGISTER);
     }

     if (ret == VA_USERNAME_EXISTS) {
        global_warning("That username is in use.");
        global_warning("Please select another.");
        t_open(T_REGISTER);
     }

     /*
        These are all the admin's fault.
     */
     if (ret <= -3) {
        if (ret == VA_BAD_D_DIR)
           global_error("Although the domain you requested is available for signup, " \
                        "this server does not yet support it.", 0, 0);        
        else
          global_error("Unable to add user due to bad permissions.", 0, 0);        
     }
  }

  /*
     Verify is on
  */
  if ((verify == 1) && (cemail) && (*cemail)) {
     ret = send_email();
     if (ret == 0) {
        del_user(user, dom);
/*
        Let send_email() set warnings...

        global_warning("Out of resources.");
        global_warning("Please wait, and try again.");
*/
        if (allowpassword)
           t_open(T_REGISTER_WITH_PASSWORD);
        else
           t_open(T_REGISTER);
     }

     else if (ret == 1) {
        field_trigger();

        if (redirect) {
           printf("Location: %s\n\n", redirect);
           return;
        }
        
        if (allowpassword)
           t_open(T_SUCCESS_WITH_PASSWORD);
        else
           t_open(T_SUCCESS);
     }
  
     else if (ret == 2) {
        global_warning("Invalid email address.");

        if (allowpassword)
           t_open(T_REGISTER_WITH_PASSWORD);
        else
           t_open(T_REGISTER);
     }  

     else
        tfatal();  
  }

  /*
     Verify is off
  */
  else {
     field_trigger();

     if (redirect) {
        printf("Location: %s\n\n", redirect);
        return;
     }

     if (allowpassword)
        t_open(T_SUCCESS_WITH_PASSWORD);
     else
        t_open(T_SUCCESS);
  }
}

int send_email(void)
{
  char *p = NULL, *email = NULL, b[500] = { 0 };
  int fd0[2] = { 0, 0 }, pid = 0, ret = 0, eret = 0,
      cout = 0, cin = 0, pout = 0, pin = 0;
  char ch = 0;
  
  /*
     Check for weird characters in
     current email address.
  */
  for (p = cemail; *p; p++) {
      if (((*p < '0') || (*p > '9')) &&
          ((*p < 'a') || (*p > 'z')) &&
          ((*p < 'A') || (*p > 'Z')) &&
          ((*p != '-') && (*p != '@') && (*p != '.') && (*p != '_')))
         return 2;      
  }
  
  email = mstrdup(cemail);
  for (p = email; *p; p++) {
      if (*p == '@') {
         *p++ = '\0';
         break;
      }
  }  

  if (!(*p))
     return 2;

  ret = check_badhosts(p);
  if (ret) {
     global_warning("The current email address you provided, and all it's users, have been denied service by this administrator.");
     global_warning("Please provide another email address.");
   
     return 0;
  }

  ret = pipe(fd0);
  if (ret == -1) {
     global_warning("Out of resources, please try again later.");
     return 0;
  }

  pin = fd0[0];
  cout = fd0[1];

  ret = pipe(fd0);
  if (ret == -1) {
     global_warning("Out of resources, please try again later.");
     return 0;
  }

  cin = fd0[0];
  pout = fd0[1];

  pid = fork();
  if (pid == 0) {
     /*
         Give parent a few seconds to spool it's message.
         This may be needed on slower systems, or on systems
         which swap it's processes out now and then.
     */
     sleep(3);

     close(pin);
     close(pout);

     close(0);

     ret = fcntl(cin, F_DUPFD, 0);
     if (ret == -1) {
        printf("h-DChild descriptor duplication failed\n");
        exit(0);
     }

     close(cin);

     close(1);

     ret = fcntl(cout, F_DUPFD, 1);
     if (ret == -1) {
        printf("h-DChild descriptor duplication failed\n");
        exit(0);
     }

     close(cout);

     close(2);

     ret = fcntl(1, F_DUPFD, 2);
     if (ret == -1) {
        printf("h-DChild descriptor duplication failed\n");
        exit(0);
     }

     eret = execl("/var/qmail/bin/qmail-remote", "/var/qmail/bin/qmail-remote", p, "register@inter7.com", cemail, NULL);
     if (eret == -1)
        printf("h-DChild execution failed\n");
     
     exit(0);
  }

  else if (pid == -1) {
     global_warning("Out of resources, please try again later.");
     return 0;
  }

  else if (pid) {
    close(cin);
    close(cout);

    et_open(pout, ET_EMAIL);
 
    if (advertise) {
       memset((char *)b, 0, 500);
       snprintf(b, 500, "\n" \
                        "--------------------------------\n" \
                        "vQregister v%s - www.inter7.com\n" \
                        "--------------------------------\n",
                        VQREGISTER_VERSION);

       ret = write(pout, (char *)b, strlen(b));
       if (ret < strlen(b)) {
          del_user(user, dom);
          global_warning("Message spool failed");
          t_open(T_FAILURE);
       }
    }

    close(pout);

    memset((char *)b, 0, 500);
    ret = read(pin, (char *)b, 500);
    if (ret < 1) {
       del_user(user, dom);
       global_warning("Message delivery response read failed");
       t_open(T_FAILURE);
    }     

    /*
       This is where we handle the various
       qmail-remote returns.
    */
    
    if ((*b == 'Z') || (*b == 'D')) {
       del_user(user, dom);
       global_warning(b + 1);
       t_open(T_FAILURE);
    }
   
    else if ((*b == 'h') || (*b == 's')) {
       del_user(user, dom);
       global_warning(b + 3);
       t_open(T_FAILURE);
    }

    else {
       if ((*(b + 2) == 'D') || (*(b + 2) == 'Z')) {
          del_user(user, dom);
          global_warning(b + 3);
          t_open(T_FAILURE);
       }
    }
       
    close(pin);

    return 1;
  }

  else
     return 3;
}

char *setup_var(char *name, char *tc)
{
  char *var = NULL;

  var = cgi_is_var(name);
  if (var == NULL) {
     global_warning("Missing required data");
     global_warning(name);

     if (allowpassword)
        t_open(T_REGISTER_WITH_PASSWORD);
     else
        t_open(T_REGISTER);
  }

  global_par(tc, var);

  return var;
}



syntax highlighted by Code2HTML, v. 0.9.1