/***************************************************************************
                          notificationhttp.cpp  -  description
                             -------------------
    begin                : Mon Dec 8 2003
    copyright            : (C) 2003 by Wei Zheng
    email                : v_zheng@yahoo.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 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "notificationhttp.h"
#define ENDSTRING "f680fa9ba884447fc820046655b2b9da"

notificationhttp::notificationhttp(char * name, char * pass, char * addr, char * proxyaddr, int proxyport){
  auth.get_namepass(name,pass);

  if(proxyaddr!=NULL && proxyport!=0)
  {
    strcat(myhttp.proxyaddr,proxyaddr);
    myhttp.proxyport = proxyport;
  }
  communication();
}
notificationhttp::~notificationhttp(){
}

int notificationhttp::communication(){

  if(myhttp.proxyport!=0)
  {
    if(myhttp.make_connect(myhttp.proxyaddr,myhttp.proxyport)==-1)
    {
      myhttp.debug("ERR ADDR:%s PORT:%d unable to connect\n",myhttp.proxyaddr,myhttp.proxyport);
      return 1;
    }
    else
    {
      myhttp.debug("OK ADDR:%s PORT:%d able to connect\n",myhttp.proxyaddr,myhttp.proxyport);
    }
  }

  strcat(myhttp.prp.ip,NOTIFICATIONHTTPPROXY);
  strcat(myhttp.prp.action,"open");
  strcat(myhttp.prp.server,"NS");

  myhttp.send_comm(1,"","");
  myhttp.reci_mesg();

  myhttp.send_comm(1,"VER","MSNP9 MSNP8 MSNP7 CVR0\r\n");
  myhttp.reci_mesg();

  myhttp.send_comm(1,"CVR","0x0409 winnt 5.1 i386 MSNMSGR 6.0.0602 MSMSGS %s\r\n",auth.username);
  myhttp.reci_mesg();

  myhttp.send_comm(1,"USR","TWN I %s\r\n",auth.username);
  myhttp.reci_mesg();

  if(myhttp.get_resp()==0)
    auth.get_challenge(myhttp.tmpresp.point[4]);
  else
    return 1;

  if(myhttp.proxyport!=0)
    auth.renew(myhttp.proxyaddr,myhttp.proxyport);

  if(auth.do_auth()!=1)
  {
    fprintf(stderr,"Authentication Failed\n");
    return 1;
  }

  myhttp.send_comm(1,"USR","TWN S %s\r\n",auth.challenge);
  myhttp.reci_mesg();

  myhttp.tmpresp.flush();
  strcat(myhttp.tmpresp.line,myhttp.recimesgbuf);
  myhttp.tmpresp.makearray();
  if(strcmp(myhttp.tmpresp.point[0],"USR")!=0 || strcmp(myhttp.tmpresp.point[2],"OK")!=0)
    return 1;

  myhttp.send_comm(1,"SYN","1069\r\n");	
  myhttp.reci_mesg();

  myhttp.send_comm(1,"CHG","NLN 0\r\n");

  while(1)
  {
    if(myhttp.reci_mesg()>0)
    {
      while(1)
      {
        if(myhttp.get_resp()==0)
        {
          if(strcmp(myhttp.tmpresp.point[0],"CHL")==0)
          {
            strcat(ascii_original,myhttp.tmpresp.point[2]);
            strcat(ascii_original,"Q1P7W2E4J9R8U3S5");
            MD5Digest();
            myhttp.send_comm(0,"QRY","msmsgs@msnmsgr.com %d\r\n%s",strlen(ascii_digest),ascii_digest);
          }
          else if(strcmp(myhttp.tmpresp.point[0],"MSG")==0)
            myhttp.get_mesg(atoi(myhttp.tmpresp.point[3]));
          else if(strcmp(myhttp.tmpresp.point[0],"ILN") == 0)
            usersqueue.add_online_user(myhttp.tmpresp.point[3],myhttp.tmpresp.point[4]);
          else if(strcmp(myhttp.tmpresp.point[0],"NLN") == 0)
            usersqueue.add_online_user(myhttp.tmpresp.point[2],myhttp.tmpresp.point[3]);
          else if(strcmp(myhttp.tmpresp.point[0],"FLN") == 0)
            usersqueue.del_online_user(myhttp.tmpresp.point[1]);
          else if(strcmp(myhttp.tmpresp.point[0],"OUT") == 0)
            break;
          else if(strcmp(myhttp.tmpresp.point[0],"RNG")==0)
          {
            myhttp.debug_switch = 0;
            usersqueue.current_user=usersqueue.search_online_user(myhttp.tmpresp.point[5]);
            if(usersqueue.current_user==NULL)
            {
              usersqueue.add_online_user(myhttp.tmpresp.point[5],myhttp.tmpresp.point[6]);
              usersqueue.current_user=usersqueue.search_online_user(myhttp.tmpresp.point[5]);
            }
            memset(usersqueue.current_user->userinfop->ip,0,sizeof(usersqueue.current_user->userinfop->ip));
            strncat(usersqueue.current_user->userinfop->ip,myhttp.tmpresp.point[2],(strstr(myhttp.tmpresp.point[2],":")-myhttp.tmpresp.point[2])/sizeof(char));
            memset(usersqueue.current_user->userinfop->port,0,sizeof(usersqueue.current_user->userinfop->port));
            strcat(usersqueue.current_user->userinfop->port,strstr(myhttp.tmpresp.point[2],":")+1);
            memset(usersqueue.current_user->userinfop->sessionid,0,sizeof(usersqueue.current_user->userinfop->sessionid));
            strcat(usersqueue.current_user->userinfop->sessionid,myhttp.tmpresp.point[1]);
            memset(usersqueue.current_user->userinfop->authid,0,sizeof(usersqueue.current_user->userinfop->authid));
            strcat(usersqueue.current_user->userinfop->authid,myhttp.tmpresp.point[4]);
            strcat(usersqueue.current_user->userinfop->proxyaddr,myhttp.proxyaddr);
            usersqueue.current_user->userinfop->proxyport=myhttp.proxyport;
            if(usersqueue.current_user->pid!=0)
              kill(usersqueue.current_user->pid,SIGQUIT);
            if((usersqueue.current_user->pid=fork())==0)
            {
              dialog(usersqueue.current_user->userinfoid);
              exit(0);
            }
          }
        }
        else
          break;
      }
    }
    myhttp.send_comm(1,"","");
  }
}

int notificationhttp::dialog(int userinfoid)
{
  int comm;

  pthread_t execute_thread;
  pthread_t write_thread;
	void * thread_result;

  myhttp.debug_switch = 0;
  myhttp.userinfop = (userinfo *) shmat(userinfoid, (void *)0, 0);
  if(myhttp.userinfop == (void *)-1)  return -1;

  if(myhttp.proxyport!=0)
  {
    if(myhttp.make_connect(myhttp.proxyaddr,myhttp.proxyport)==-1)
    {
      myhttp.debug("ERR %s:%d unable to connect\n",myhttp.proxyaddr,myhttp.proxyport);
      return 1;
    }
    else
    {
      myhttp.debug("OK %s:%d able to connect\n",myhttp.proxyaddr,myhttp.proxyport);
    }
  }

  memset(myhttp.prp.ip,0,sizeof(myhttp.prp.ip));
  strcat(myhttp.prp.ip,myhttp.userinfop->ip);
  strcat(myhttp.prp.action,"open");
  strcat(myhttp.prp.server,"SB");
  memset(myhttp.prp.sessionid,0,sizeof(myhttp.prp.sessionid));

  printf("ip:%s action:%s server:%s\n",myhttp.userinfop->prp.ip,myhttp.userinfop->prp.action,myhttp.userinfop->prp.server);
  myhttp.send_comm(1,"","");
  myhttp.reci_mesg();

  myhttp.send_comm(1,"ANS","%s %s %s\r\n",auth.username,myhttp.userinfop->authid,myhttp.userinfop->sessionid);
  myhttp.reci_mesg();

  myhttp.get_resp();
  if(strcmp(myhttp.tmpresp.point[0],"IRO")!=0 && strcmp(myhttp.tmpresp.point[4],myhttp.userinfop->username)!=0)
    return -1;

  myhttp.send_mesg();
  myhttp.reci_mesg();
  myhttp.get_resp();
  if(strcmp(myhttp.tmpresp.point[0],"ANS")!=0 && strcmp(myhttp.tmpresp.point[1],"OK")!=0 )
    return -1;

  pipe(myhttp.pipefd);
  myhttp.sendmesgrea = 0;

  if(pthread_create(&execute_thread,NULL,thread_execute_http,(void *) &myhttp) != 0)
  {
    perror("Thread creation failed");
    return -1;
  }

  if(pthread_create(&write_thread,NULL,thread_write_http,(void *) &myhttp) != 0)
  {
    perror("Thread creation failed");
    return -1;
  }

  while(1)
  {
    myhttp.send_mesg();
    if(myhttp.reci_mesg()>0)
    {
      comm = 0;
      while(1)
      {
        if(myhttp.get_resp()==0)
        {
          if(strcmp(myhttp.tmpresp.point[0],"MSG")==0)
          {
            if(myhttp.get_mesg(atoi(myhttp.tmpresp.point[3]))==1)
              sem_post(&myhttp.bin_sem_finline_isfull);
          }
          else if(strcmp(myhttp.tmpresp.point[0],"BYE")==0)
          {
            goto exit;
          }
        }
        else
          break;
      }
    }
  }

  exit:

  if (pthread_cancel(execute_thread) != 0)
  {
    perror("Thread cancelation failed");
    return -1;
  }

  if (pthread_join(execute_thread, &thread_result) != 0)
  {
    perror("Thread join failed");
    return -1;
  }

  if (pthread_cancel(write_thread) != 0)
  {
    perror("Thread cancelation failed");
    return -1;
  }

  if (pthread_join(write_thread, &thread_result) != 0)
  {
    perror("Thread join failed");
    return -1;
  }
	myhttp.make_close();
	return 0;
}

/** No descriptions */
void * thread_execute_http(void * para)
{
  int fd;
  int i,exit_flag;
  char hostname[56];
  char username[56];
  char password[56];
  http * httpp;
  httpp = (http *) para;

  if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL)!= 0) {
    perror("Thread pthread_setcancelstate failed");
    pthread_exit(0);
  }

  if(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL)!= 0) {
    perror("Thread pthread_setcanceltype failed");
    pthread_exit(0);
  }

  START:

  strcat(httpp->sendmesgbuf,"Protocol(ssh/ftp):");
  httpp->sendmesglen = strlen(httpp->sendmesgbuf);
  httpp->sendmesgrea = 1;

  sem_wait(&(httpp->bin_sem_finline_isfull));

  if(strcmp(httpp->finline,"ssh")==0)
  {
    memset(httpp->finline,0,strlen(httpp->finline));

    dup2(httpp->pipefd[1],STDOUT_FILENO);
    dup2(httpp->pipefd[1],STDERR_FILENO);
    close(httpp->pipefd[1]);

    SSHSTART:

    memset(hostname,0,sizeof(hostname));
    memset(username,0,sizeof(username));

    strcat(httpp->sendmesgbuf,"hostname:");
    httpp->sendmesglen = strlen(httpp->sendmesgbuf);
    httpp->sendmesgrea = 1;

    sem_wait(&(httpp->bin_sem_finline_isfull));
    strcat(hostname,httpp->finline);
    memset(httpp->finline,0,strlen(httpp->finline));

    strcat(httpp->sendmesgbuf,"username:");
    httpp->sendmesglen = strlen(httpp->sendmesgbuf);
    httpp->sendmesgrea = 1;

    sem_wait(&(httpp->bin_sem_finline_isfull));
    strcat(username,httpp->finline);
    memset(httpp->finline,0,strlen(httpp->finline));

    if (-1==(fd = exp_spawnl("ssh","ssh","-l",username,hostname,(char *)0)))
    {
      perror("ssh failed");
      exit(-1);
    }

    PASSWORD:
    switch(exp_expectl(fd,
      exp_glob,"*(yes/no)?",0,
      exp_glob,"*password:",1,
      exp_glob,"Temporary failure in name resolution",2,
      exp_end)){
    case 0:
      write(fd,"yes\r",4);
      goto PASSWORD;
      break;
    case 1:
      while(1)
      {
        strcat(httpp->sendmesgbuf,"password:");
        httpp->sendmesglen = strlen(httpp->sendmesgbuf);
        httpp->sendmesgrea = 1;

        sem_wait(&(httpp->bin_sem_finline_isfull));
        strcat(httpp->finline,"\n\r");
        write(fd,httpp->finline,strlen(httpp->finline));
        memset(httpp->finline,0,strlen(httpp->finline));

        switch(exp_expectl(fd,
          exp_glob,"Last login:*",0,
          exp_glob,"again",1,
          exp_glob,"publickey,password,keyboard-interactive",2,
          exp_end)){
        case 0:
          i = 0;
          printf("%s\n",ENDSTRING);
          break;
        case 1:
          i = 1;
          printf("%s\n",ENDSTRING);
          break;
        case 2:
          i = 2;
          printf("%s\n",ENDSTRING);
          break;
        }
        if(i == 0)
          break;
        if(i == 2)
        {
          goto SSHSTART;
        }
      }
      break;
    case 2:
      printf("%s\n",ENDSTRING);
      sleep(1);
      goto SSHSTART;
    default:
      printf("%s\n",ENDSTRING);
      sleep(1);
      goto SSHSTART;
    }

    switch(exp_expectl(fd,exp_glob,"*]# ",0,exp_glob,"*]$ ",1,exp_end)){
      case 0:
        write(fd,"sh\n",3);
        break;
      case 1:
        write(fd,"sh\n",3);
        break;
    }

    while(1)
    {
      switch(exp_expectl(fd,
        exp_glob,"\n",0,
        exp_glob,"sh-2.05a# ",1,
        exp_glob,"sh-2.05a$ ",1,
	exp_glob,"sh-2.05b# ",1,
	exp_glob,"sh-2.05b$ ",1,
        exp_end)){
      case 0:
        break;
      case 1:
        printf("\n%s\n",ENDSTRING);
        sem_wait(&(httpp->bin_sem_finline_isfull));
        if(strncmp(httpp->finline,"exit",4)==0)
          i = 1;
        else
          i = 0;
        strcat(httpp->finline,"\n");
        write(fd,httpp->finline,strlen(httpp->finline));
        memset(httpp->finline,0,strlen(httpp->finline));
        break;
      case EXP_TIMEOUT:
        printf("\n%s\n",ENDSTRING);
        sem_wait(&(httpp->bin_sem_finline_isfull));
        if(strncmp(httpp->finline,"exit",4)==0)
          i = 1;
        else
          i = 0;
        strcat(httpp->finline,"\n");
        write(fd,httpp->finline,strlen(httpp->finline));
        memset(httpp->finline,0,strlen(httpp->finline));
        break;
      }
      if(i == 1)
      {
        close(fd);
        goto SSHSTART;
      }
    }
    exit_flag = 1;
  }
  else if(strcmp(httpp->finline,"ftp")==0)
  {
    struct passwd *pw = NULL;
    struct spwd *sp;
    char *salt, *p;

    memset(httpp->finline,0,strlen(httpp->finline));

    PROMPTUSERNAME:
    pw = NULL;
    pw = getpwuid(getuid());

    sp = getspnam(pw->pw_name);
    pw->pw_passwd = sp->sp_pwdp;
    salt = pw->pw_passwd;

    memset(username,0,sizeof(username));
    memset(password,0,sizeof(password));

    sprintf(username,"Current username:%s password:??????",pw->pw_name);
    strcat(httpp->sendmesgbuf,username);
    httpp->sendmesglen = strlen(httpp->sendmesgbuf);
    httpp->sendmesgrea = 1;

    sem_wait(&(httpp->bin_sem_finline_isfull));
    strncat(password,httpp->finline,sizeof(password));
    memset(httpp->finline,0,strlen(httpp->finline));

    p = crypt(password,salt);
    if(strcmp(p,pw->pw_passwd)!=0)
    {
      strcat(httpp->sendmesgbuf,"error");
      httpp->sendmesglen = 5;
      goto PROMPTUSERNAME;
    }

    setenv("HOME", pw->pw_dir, 1);
    setenv("SHELL", pw->pw_shell, 1);
    setenv("USER", pw->pw_name, 1);
    setenv("LOGNAME", pw->pw_name, 1);

    chdir(pw->pw_dir);

    dup2(httpp->pipefd[1],STDOUT_FILENO);
    dup2(httpp->pipefd[1],STDERR_FILENO);
    close(httpp->pipefd[1]);

    FTPSTART:

    if (-1 == (fd = exp_spawnl("ftp","ftp",(char *)0)))
    {
      perror("ftp failed");
      exit(-1);
    }

    exit_flag = 0;
    while(1)
    {
      switch(exp_expectl(fd,
        exp_glob,"ftp> ",0,
        exp_glob,"220 *Name*:",1,
        exp_glob,"331 *Password*:",1,
        exp_glob,"221 ",2,
        exp_end)){
      case 0:
        printf("\n%s\n",ENDSTRING);
        sem_wait(&(httpp->bin_sem_finline_isfull));
        if(strncmp(httpp->finline,"exit",4)==0)
          exit_flag = 1;;
        strcat(httpp->finline,"\n");
        write(fd,httpp->finline,strlen(httpp->finline));
        memset(httpp->finline,0,strlen(httpp->finline));
        break;
      case 1:
        printf("\n%s\n",ENDSTRING);
        sem_wait(&(httpp->bin_sem_finline_isfull));
        strcat(httpp->finline,"\r");
        write(fd,httpp->finline,strlen(httpp->finline));
        memset(httpp->finline,0,strlen(httpp->finline));
        break;
      case 2:
        goto FTPSTART;
        break;
      case EXP_TIMEOUT:
        printf("\n%s\n",ENDSTRING);
        sem_wait(&(httpp->bin_sem_finline_isfull));
        if(strncmp(httpp->finline,"exit",4)==0)
          exit_flag = 1;;
        strcat(httpp->finline,"\n");
        write(fd,httpp->finline,strlen(httpp->finline));
        memset(httpp->finline,0,strlen(httpp->finline));
        break;
      }
      if(exit_flag == 1)
        goto FTPSTART;
    }
  }
  else
  {
    memset(httpp->finline,0,strlen(httpp->finline));
    goto START;
  }

  pthread_exit(0);
}

int get_http_line(int fd,char *buf,int len){
  int got=0;
  int err;
  while(1)
  {
    if(got==len)
      return(got);
    err=read(fd,&buf[got],1);
    if(err!=1)
    {
      if(errno!=EINTR)
        return(-1);
      return(-3);
    }
    if(buf[got] <= 0)
    {
      buf[got] = 32;
    }
    else if(buf[got]=='\n')
    {
      return(got+1);
    }
    got++;
  }
}

/** No descriptions */
void * thread_write_http(void * para)
{
  http * httpp;
  httpp = (http *) para;
  char myline[256];
  int result;

  if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL)!= 0) {
    perror("Thread pthread_setcancelstate failed");
    pthread_exit(0);
  }

  if(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL)!= 0) {
    perror("Thread pthread_setcanceltype failed");
    pthread_exit(0);
  }

  while(1)
  {
    memset(myline,0,sizeof(myline));
    result = 0;
    result = get_http_line(httpp->pipefd[0],myline,sizeof(myline));
    if(result > 0)
    {
      while(MESGSIZE - httpp->sendmesglen <= result)
      {
        httpp->sendmesgrea = 1;
        sleep(1);
      }

      if(strstr(myline,ENDSTRING)!=NULL)
      {
        httpp->sendmesgrea = 1;
      }
      else
      {
        memcpy(httpp->sendmesgbuf+httpp->sendmesglen,myline,result);
        httpp->sendmesglen += result;
      }
    }
  }
  pthread_exit(0);
}
