/*
 * kakumei.c
 *
 * Private group web.
 *
 * Author: Dario Rodriguez dario@softhome.net
 * This progran is licensed under the terms of the Affero GPL v1+
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "gen_res.h"
#include "socklib.h"
#include "webkernel.h"

#define INVITATIONUSER "invitation"
#define DATADIR "data"
#define INVITESDIR "data/invitations"
#define USERSDIR "data/users"
#define POSTSDIR "data/posts"
#define SESSIONSDIR "data/sessions"

typedef struct kakumei {
        sselect *ssel;
        wk *web;
} kakumei;


static int signal_init(int signum, void (*fn)(int));
static void sigint(int signum);
volatile int sigint_flag=0;

wk_action callback_http(wk *web, int connid, wk_uri *uri, void *userptr);
wk_action http_login(wk *web, int connid, wk_uri *uri, void *userptr);
wk_action http_newuser(wk *web, int connid, wk_uri *uri, void *userptr);

int pass_check(char *user, char *passwd);
char *session_new(char *user, char *session, int sessionsize);



int
main(int argc, char *argv[])
{
        int port;
        int timeout=500;
        kakumei *ka,kastore;
        memset(&kastore,0,sizeof(kastore));
        ka=&kastore;
        if(argc!=2) {
                printf("Syntax: %s port\n",argv[0]);
                return(1);
        }
        port=atoi(argv[1]);
        if((ka->ssel=sselect_init())==NULL) {
                fprintf(stderr,"ERROR: insufficient memory\n");
                return(1);
        }
        if((ka->web=wk_init(port,ka->ssel,NULL,callback_http,NULL,NULL,ka))==NULL) {
                sselect_free(ka->ssel),ka->ssel=NULL;
                fprintf(stderr,"ERROR: couldn't init web server\n");
                return(2);
        }
        sigint_flag=0;
        signal_init(SIGINT,sigint);
        while(!sigint_flag) {
                sselect_wait(ka->ssel,timeout);
                wk_service(ka->web);
        }
        wk_free(ka->web),ka->web=NULL;
        sselect_free(ka->ssel),ka->ssel=NULL;
        return(0);
}

wk_action
callback_http(wk *web, int connid, wk_uri *uri, void *userptr)
{
        kakumei *ka=(kakumei *)userptr;
        resindex *res;
        char partialpath[1024];
        char *ptr;
        if(ka==NULL)
                return(wkact_finished);
        printf("http: %s\n",uri->path);
        strncpy(partialpath,uri->path,sizeof(partialpath)-1);
        partialpath[sizeof(partialpath)-1]='\0';
        if((ptr=strchr(partialpath,'?'))!=NULL)
                *ptr='\0';
        if((strcmp(uri->path,"/")==0 && (res=res_find(resindexdata,"index.html"))!=NULL) ||
          (partialpath[0]=='/' && (res=res_find(resindexdata,partialpath+1))!=NULL)) {
                wk_serve_buffer_as_file(web,connid,res->data,res->len,mime_getdefault(res->name,"application/octet-stream"));
                return(wkact_finished);
        }
        if(memcmp(uri->path,"/login?",7)==0) {
                return(http_login(web,connid,uri,userptr));
        } else if(memcmp(uri->path,"/newuser?",9)==0) {
                return(http_newuser(web,connid,uri,userptr));
        }
        printf("URI not found: %s\n",uri->path);
        wk_serve_error(web,connid,wkerr_notfound);
        return(wkact_finished);
}

static int
signal_init(int signum, void (*fn)(int))
{
        struct sigaction sa;
        sa.sa_handler=fn;
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        return(sigaction(signum,&sa,0));
}

static void
sigint(int signum)
{
        sigint_flag=1;
}

wk_action
http_login(wk *web, int connid, wk_uri *uri, void *userptr)
{
        char u[128],p[128];
        char reply[1024];
        char invitepath[1024];
        char userpath[1024];
        char session[1024];
        struct stat st;
        if(wk_uri_copyvar(uri,"u",u,sizeof(u))==NULL)
                u[0]='\0';
        if(wk_uri_copyvar(uri,"p",p,sizeof(p))==NULL)
                p[0]='\0';
        /* check for invitation */
        snprintf(invitepath,sizeof(invitepath),"%s/%s",INVITESDIR,p);
        invitepath[sizeof(invitepath)-1]='\0';
        snprintf(userpath,sizeof(userpath),"%s/%s/passwd",USERSDIR,u);
        userpath[sizeof(userpath)-1]='\0';
        if(strcmp(u,INVITATIONUSER)==0 &&
          strchr(p,'/')==NULL && strchr(p,'.')==NULL &&
          stat(invitepath,&st)==0 && S_ISREG(st.st_mode)) {
                /* valid invitation */
                snprintf(reply,sizeof(reply),"/newuser.html?i=%s",p);
                reply[sizeof(reply)-1]='\0';
                wk_serve_buffer_as_file(web,connid,reply,strlen(reply),"text/plain");
                return(wkact_finished);
        } else if(strchr(u,'/')==NULL && strchr(u,'.')==NULL &&
          stat(userpath,&st)==0 && S_ISREG(st.st_mode) && pass_check(u,p)==0 &&
          session_new(u,session,sizeof(session))!=NULL) {
                /* valid login */
                snprintf(reply,sizeof(reply),"/posts.html?s=%s",session);
                reply[sizeof(reply)-1]='\0';
                wk_serve_buffer_as_file(web,connid,reply,strlen(reply),"text/plain");
                return(wkact_finished);
        }
        wk_serve_error(web,connid,wkerr_internal);
        return(wkact_finished);
}

wk_action
http_newuser(wk *web, int connid, wk_uri *uri, void *userptr)
{
#warning TODO
        wk_serve_error(web,connid,wkerr_internal);
        return(wkact_finished);
}


int
pass_check(char *user, char *passwd)
{
#warning TODO
        return(-1);
}

char *
session_new(char *user, char *session, int sessionsize)
{
#warning TODO
        return(NULL);
}