#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#include "tcp.h"
#include "url.h"
#include "msq.h"

#define UD_KEY 7639

extern int	errno;
extern char	*syserrlist[];

int snd_msqid;
int nopipe=0;

FILE *open_url_file(BWindow *bwindow, URL *u);
FILE *open_url_http(BWindow *bwindow, URL *u);
FILE *open_url_ftp(BWindow *bwindow, URL *u);

#ifdef FORK_DOWNLOAD
/* return a pointer to a anonymous shared memory segment of size "size"
   which will persist across fork() but will disappear when all processes
   exit 

   The memory is not zeroed 

   This function uses system5 shared memory. It takes advantage of a property
   that the memory is not destroyed if it is attached when the id is removed
   */
void *shm_setup(int size)
{
	int shmid;
	void *ret;

	shmid = shmget(IPC_PRIVATE, size, SHM_R | SHM_W);
	if (shmid == -1) {
		printf("can't get shared memory\n");
		exit(1);
	}
	ret = (void *)shmat(shmid, 0, 0);
	if (!ret || ret == (void *)-1) {
		printf("can't attach to shared memory\n");
		return NULL;
	}

	/* the following releases the ipc, but note that this process
	   and all its children will still have access to the memory, its
	   just that the shmid is no longer valid for other shm calls. This
	   means we don't leave behind lots of shm segments after we exit 

	   See Stevens "advanced programming in unix env" for details
	   */
	shmctl(shmid, IPC_RMID, 0);
	
	return ret;
}
#endif

void sigpipe_handler(int sig)
{
  nopipe=1;
  g_print("Got SIGPIPE\n");
  signal(sig, sigpipe_handler);
}

URL *open_url(BWindow *bwindow, char *url)
{
  fd_set fds;
  FILE *s;
  char msg[URL_LEN];
  URL *u;
  int nread=0, nsrc=0;
  int total_read;
  struct timeval tv;
  int read_all=0;

#ifdef FORK_DOWNLOAD
  int pid;
  int status;
  int shmkey_ud = 6293;
  int shmid_ud;


  if((ud=(url_data)shm_setup(sizeof(_url_data))) == NULL) {
    perror("shmsetup");
    exit(1);
  }

  pid = fork();
  if(pid==0) {
#else /* !FORK_DOWNLOAD */
  /*ud = (url_data)pmalloc(sizeof(_url_data), "url_data");*/
#endif

    if(signal(SIGPIPE, sigpipe_handler) == SIG_ERR) {
      perror("child: signal");
      _exit(1);
    }

#ifdef FORK_DOWNLOAD
    snd_msqid = msq_snd_init();
#endif

    fprintf(stderr, "in open_url, need url rel to %s\n", bwindow->current->url);
    u = parse_url(url, bwindow->current->url);

#if 0
    g_print("about to strcpy(ud->url,u->url) %s\n",u->url);
    strcpy(ud->url, u->url);
#endif

#ifdef FORK_DOWNLOAD
    sprintf(msg, "");
    msq_snd(snd_msqid, bwindow, msg);
#endif

    switch(u->protocol) {
      case URL_FILE:
         s=open_url_file(bwindow, u);
         g_print("Opened file fd: %d\n", (int)s);
         break;
      case URL_HTTP:
         s=open_url_http(bwindow, u);
         break;
      case URL_FTP:
         s=open_url_ftp(bwindow, u);
         break;
      default:
         s=NULL;
         break;
   }

  if(!s) {
    sprintf(msg, "Invalid URL: %s", url);
    perror(msg);
#if 0
    make_alert(bwindow, msg);
#endif
    return(FALSE);
  }

  u->buf[0] = '\0';
  total_read=0;
  nread=1;

  switch(u->protocol) {
    case URL_FILE:
      total_read = fread(u->buf, 1, BUF_LEN-1, s);
#ifdef DEBUG
      g_print("URL_FILE: read %d bytes\n", total_read);
      g_print("%s\n", u->buf);
#endif
      break;
    case URL_HTTP:
    case URL_FTP:

      tv.tv_sec = 1;
      tv.tv_usec = 0;
      while (!read_all && nread != 0) {
        FD_ZERO(&fds);
        FD_SET((int)s, &fds);
        if(select((int)s+1, &fds, NULL, NULL, &tv) > 0) {
          if (FD_ISSET((int)s, &fds)) {
            nread = read((int)s, &(u->buf[total_read]), BUF_LEN-1-total_read);
            if(nread==-1) {
              if(errno!=EAGAIN) read_all=1;
            }
#ifdef DEBUG
            g_print("%s\n", &u->buf[total_read]);
#endif
            total_read += nread;
          }
        }
       /* do_background_processing(); */
      }
      break;
    default:
      break;
  }

  nopipe=0;
  if(total_read==0) {
      perror("child: Could not read file descriptor");
      sprintf(msg, "Invalid URL: %s", url);
      /*make_alert(bwindow, msg);*/
      g_print("Invalid URL: -->%s<--\n", url);
#ifdef FORK_DOWNLOAD
      _exit(0);
#endif
  }
  u->buf[total_read] = '\0';

  switch(u->protocol) {
    case URL_FILE:
      u->src = u->buf;
      nsrc = total_read;
      u->hdr = NULL;
      break;
    case URL_HTTP:
      u->hdr = u->buf;
      u->src = strstr(u->buf, "\r\n\r\n") + 2;
      *(u->src) = '\0';
      u->src += 2;
      nsrc = total_read - (u->src - u->buf);
      break;
    case URL_FTP:
      u->src = u->buf;
      nsrc = total_read;
      u->hdr = NULL;
      break;
    default:
      break;
  }

#ifdef FORK_DOWNLOAD
    _exit(0);
  } else if(pid==-1) {
     perror("Unable to fork for download");
  }

  waitpid(pid, &status, 0);
  if(status != 0) {
   fprintf(stderr, "child exited status %d\n", status);
  }
#endif

#ifdef DEBUG
  g_print("parent:\n%s\n^^parent^^\n", u->src);
#endif

  return u;
   
}

FILE *open_url_file(BWindow *bwindow, URL *u)
{
   g_print("local file -->%s<--\n", u->path);
   return fopen(u->path, "r");
}

FILE *open_url_http(BWindow *bwindow, URL *u)
{
  char buf[LINELEN+1];
  char msg[256];
  int s;
#if 0
  int n;
  fd_set set;
#endif
 
#ifdef DEBUG
 g_print("in open_url_http()\n");
#endif
 
  sprintf(msg, "Connecting to %s : %d ...", u->host, u->port);
#ifdef FORK_DOWNLOAD
  msq_snd(snd_msqid, bwindow, msg);
#endif
#ifdef DEBUG
  fprintf(stderr ,"%s\n", msg);
#endif
  
  s = connectTCPproto(u->host, u->port);
  
  sprintf(msg, "Connection established ...");
#ifdef FORK_DOWNLOAD
  msq_snd(snd_msqid, bwindow, msg);
#endif
#ifdef DEBUG
  fprintf(stderr ,"%s\n", msg);
#endif
  
  sprintf(buf, "GET %s HTTP/1.0\n\n", u->path);
 
  sprintf(msg, "Sending request (length %d):\n%s\n", strlen(buf), buf);
#ifdef FORK_DOWNLOAD
  msq_snd(snd_msqid, bwindow, msg);
#endif
#ifdef DEBUG
  fprintf(stderr ,"%s\n", msg);
#endif
       
  write((int)s, buf, strlen(buf));
    
  sprintf(msg, "Request sent.");
#ifdef FORK_DOWNLOAD
  msq_snd(snd_msqid, bwindow, msg);
#endif
#ifdef DEBUG
  fprintf(stderr ,"%s\n", msg);
#endif
  
  return (FILE *)s;
}

FILE *open_url_ftp(BWindow *bwindow, URL *u)
{
  return 0;
}

