/* GXedit
 * Copyright 1998 Patrick Lambert <drow@wildstar.net>
 *
 * This program is free software. You can use, copy and modify it under
 * the terms of the GPL. See the file COPYING for the full GPL license.
*/

#include "gxedit.h"
#ifdef USE_NET
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <stdio.h> 
#include <stdlib.h>   
#include <netdb.h>     
#include <arpa/inet.h>

char *resolve(char *string)
{
 /* return IP for host */
 struct hostent *hp;
 struct sockaddr_in from;
 memset(&from, 0, sizeof(struct sockaddr_in));
 from.sin_family = AF_INET;
 hp=gethostbyname(string);
 if(hp==NULL) return("unknown");
 else
 {
  memcpy(&from.sin_addr,hp->h_addr,hp->h_length);
  return((char *)inet_ntoa(from.sin_addr));
 }
} 

int network_fetch(char *server, char *dir, int lconvert)
{
 /* get a text file from a web server, parse if needed */
 int sockfd, len, result=1, i;
 char buf[512];
 char inchar;
 struct sockaddr_in address;
 bzero(buf, 512);
 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 address.sin_family = AF_INET;
 address.sin_addr.s_addr = inet_addr(resolve(server));
 address.sin_port = htons(80);   
 len = sizeof(address);
 print_debug("Fetching document...\n");
 if(connect(sockfd, (struct sockaddr *)&address, len)==-1)
 {
  print_debug("Error in connecting to server\n");
  return -1;
 }
 sprintf(buf, "GET %s\n", dir);
 write(sockfd, buf, strlen(buf));
 gtk_text_freeze(GTK_TEXT(text));
 hs = 0;
 while(result!=0)
 {
  bzero(buf, 512);
  for(i=0;(result=read(sockfd,&inchar,1))!='\0';i++)
  {
   buf[i]=inchar;
   if(inchar=='\n') break;
   if(i==510) break;
  }
  if(lconvert) gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL, html_to_text(buf), -1);
  else gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL, buf, -1);
 }
 gtk_text_thaw(GTK_TEXT(text));
 shutdown(sockfd, 2);
 return 0;
}

int send_email(char *to, char *subject, char *attch, char *data)
{
 /* send text as email */
 int sockfd, len;
 char buf[512];
 struct sockaddr_in address;
 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 address.sin_family = AF_INET;
 address.sin_addr.s_addr = inet_addr(resolve(mail_server));
 address.sin_port = htons(25);
 len = sizeof(address);
 if(connect(sockfd, (struct sockaddr *)&address, len)==-1)
 {
  print_debug("Can't connect to mail server\n");
  return -1;
 } 
 bzero(buf, 512);
 read(sockfd, buf, sizeof(buf));
 sprintf(buf, "MAIL FROM: %s\n", mail_from);
 write(sockfd, buf, strlen(buf));
 read(sockfd, buf, sizeof(buf));
 sprintf(buf, "RCPT TO: %s\n", to);
 write(sockfd, buf, strlen(buf));
 read(sockfd, buf, sizeof(buf));
 sprintf(buf, "DATA\n");  
 write(sockfd, buf, strlen(buf));
 read(sockfd, buf, sizeof(buf));
 sprintf(buf, "Subject: %s\n", subject);
 write(sockfd, buf, strlen(buf));
 write(sockfd, data, strlen(data));
 write(sockfd, "\n\n", strlen("\n\n"));
 if(attch!=NULL && strcasecmp(attch,""))
 {
  strncpy(tmp_name, tempnam(NULL,".gxe"), 50);
  sprintf(temp, "uuencode %s %s > %s", attch, tmp_name, tmp_name);
  system(temp);
  fd = fopen(tmp_name, "r");
  while(fgets(line, 255, fd)!=NULL)
   write(sockfd, line, strlen(line));
  if(fd!=NULL) fclose(fd);
 }
 sprintf(buf, "\n.\nQUIT\n");
 write(sockfd, buf, strlen(buf));  
 shutdown(sockfd, 2);
 print_debug("Mail sent.\n");
 return 0;
}

int post_news(char *group, char *subject)
{
 /* post text to group */
 int sockfd, len;
 char buf[512];
 char* alltext = gtk_editable_get_chars(GTK_EDITABLE (text), 0,
                 gtk_text_get_length(GTK_TEXT(text)));
 struct sockaddr_in address;
 bzero(buf, 512);
 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 address.sin_family = AF_INET;
 address.sin_addr.s_addr = inet_addr(resolve(news_server));
 address.sin_port = htons(119);
 len = sizeof(address);
 if(connect(sockfd, (struct sockaddr *)&address, len)==-1)
 {
  print_debug("Error in connecting to server\n");
  g_free(alltext);
  return -1; 
 }
 read(sockfd, buf, sizeof(buf));
 sprintf(buf, "POST\n");
 write(sockfd, buf, strlen(buf));
 read(sockfd, buf, sizeof(buf));
 sprintf(buf, "Newsgroups: %s\n", group);
 write(sockfd, buf, strlen(buf));
 sprintf(buf, "From: %s\n", mail_from);
 write(sockfd, buf, strlen(buf));
 sprintf(buf, "Subject: %s\n\n", subject);
 write(sockfd, buf, strlen(buf));
 write(sockfd, alltext, strlen(alltext));
 write(sockfd, ".\n", strlen(".\n"));
 read(sockfd, buf, sizeof(buf));
 close(sockfd);
 print_debug("Article posted. Hopefully.\n");
 g_free(alltext);
 return 0;
}

int list_groups()
{
 /* get all groups and fill in text box */
 int sockfd, len, result=1, i;
 char buf[512];
 char inchar;  
 struct sockaddr_in address;
 bzero(buf, 512);
 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 address.sin_family = AF_INET;
 address.sin_addr.s_addr = inet_addr(resolve(news_server));
 address.sin_port = htons(119);
 len = sizeof(address);
 print_debug("Fetching newsgroup list...\n");
 if(connect(sockfd, (struct sockaddr *)&address, len)==-1)
 {
  print_debug("Error in connecting to server\n");
  return -1;
 }
 read(sockfd, buf, sizeof(buf));
 sprintf(buf, "LIST newsgroups\n");
 write(sockfd, buf, strlen(buf));
 sprintf(temp, "%s/.gxedit.newsgroups", home);
 fd = fopen(temp, "w");
 if(fd==NULL)
 {
  print_debug("Can't open temp file\n");
  return -1;
 }
 while(strcmp(lindex(buf,0),"."))
 {
  bzero(buf, 512);
  for(i=0;(result=read(sockfd,&inchar,1))!='\0';i++)
  {
   *(buf+i)=inchar;
   if(strlen(buf)>510) break;
   if(inchar=='\n') break;
  }
  buf[strlen(buf)-2]=' ';
  if(!strcmp(lindex(buf,0),".")) break;
  fputs(buf, fd);
 }
 close(sockfd);
 fclose(fd);
 return 0;
}

int get_groups(char *group, char *tmp1, char *tmp2)
{
 /* get the requested newsgroup and parse in a tmp file */
 int sockfd, len, result=1, i, k;
 char buf[512], buf2[512];
 char inchar;
 struct sockaddr_in address;
 if(strlen(group)>500)
 { 
  print_debug("Group length too long\n");
  return -1;
 }
 bzero(buf, 512);
 sockfd = socket(AF_INET, SOCK_STREAM, 0); 
 address.sin_family = AF_INET;
 address.sin_addr.s_addr = inet_addr(resolve(news_server));
 address.sin_port = htons(119);
 len = sizeof(address);
 print_debug("Fetching articles list...\n");
 if(connect(sockfd, (struct sockaddr *)&address, len)==-1)
 {
  print_debug("Error in connecting to server\n");
  return -1; 
 }
 read(sockfd, buf, sizeof(buf));
 sprintf(buf2, "GROUP %s\n", group);   
 write(sockfd, buf2, strlen(buf2));
 read(sockfd, buf, sizeof(buf));
 if(*lindex(buf,0)=='4')
 {
  print_debug("No such group\n");
  return -1;
 }
 sprintf(buf2, "LISTGROUP %s\n", group);   
 write(sockfd, buf2, strlen(buf2));
 while(*lindex(buf,0)!='.')
 {
  bzero(buf, 512);
  for(i=0;(result=read(sockfd,&inchar,1))!='\0';i++)
  {
   *(buf+i)=inchar;
   if(strlen(buf)>510) break;
   if(inchar=='\n') break;
  }
  if(*lindex(buf,0)=='.') break;
  fputs(buf, fd);
 }
 fclose(fd);
 fd = fopen(tmp1, "r");
 fd2 = fopen(tmp2, "w");
 fgets(line, 255, fd);
 while(fgets(line, 255, fd)!=NULL)
 {
  k = 0;
  strcpy(buf, "blah");
  sprintf(buf2, "HEAD %s", lindex(line,0));
  write(sockfd, buf2, strlen(buf2));
  while(strcmp(lindex(buf,0),"."))
  {
   bzero(buf, 512);
   for(i=0;(result=read(sockfd,&inchar,1))!='\0';i++)
   {
    if(strlen(buf)<510) *(buf+i)=inchar;
    if(inchar=='\n') break;
   }
   buf[strlen(buf)-2]=' ';
   if(!strcmp(lindex(buf,0),"Subject:"))
   {
    line[strlen(line)-2]=' ';
    buf[strlen(buf)-1]=' ';
    bzero(temp, 1024);
    sprintf(temp, "%s - %s\n", lindex(line,0), lrange(buf,1));
    fputs(temp, fd2);
    k = 1;
   }
  }
  if(k==0)
  {
   line[strlen(line)-2]=' ';
   buf[strlen(buf)-1]=' ';
   bzero(temp, 1024);
   sprintf(temp, "%s - No subject (?!)\n", lindex(line,0));
   fputs(temp, fd2);
  }
 }
 if(fd2!=NULL) fclose(fd2);
 close(sockfd);
 return 0;
}

int get_article(char *group, char *art)
{
 /* get a single article ID from group */
 int sockfd, len, result=1, i;    
 char buf[512], buf2[512];
 char inchar;
 struct sockaddr_in address;
 if(strlen(group)>500)
 { 
  print_debug("Group length too long\n");
  return -1;
 }
 if(strlen(art)>500)
 { 
  print_debug("Group length too long\n");
  return -1;
 }
 bzero(buf, 512);
 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 address.sin_family = AF_INET;
 address.sin_addr.s_addr = inet_addr(resolve(news_server));
 address.sin_port = htons(119);
 len = sizeof(address);
 if(connect(sockfd, (struct sockaddr *)&address, len)==-1)
 {
  print_debug("Error in connecting to server\n");
  return -1; 
 }
 read(sockfd, buf, sizeof(buf));
 sprintf(buf2, "GROUP %s\n", group);
 write(sockfd, buf2, strlen(buf2));
 read(sockfd, buf, sizeof(buf));
 if(*lindex(buf,0)=='4')
 {
  print_debug("No such group\n");
  return -1;
 }
 sprintf(buf2, "ARTICLE %s\n", art);
 write(sockfd, buf2, strlen(buf2));
 gtk_text_set_point(GTK_TEXT(text), 0);
 gtk_text_forward_delete(GTK_TEXT(text),gtk_text_get_length(GTK_TEXT(text)));
 gtk_text_freeze(GTK_TEXT(text));
 while(strcmp(lindex(buf,0),"."))
 {
  bzero(buf, 512);
  for(i=0;(result=read(sockfd,&inchar,1))!='\0';i++)
  {
   *(buf+i)=inchar;
   if(strlen(buf)>510) break;
   if(inchar=='\n') break;
  }
  if(reply)
  {
   sprintf(temp, "> %s", buf);
   gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL, temp, -1);
  }
  else gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL, buf, -1);
  buf[strlen(buf)-2]=' ';
 }
 if(reply)
 {
  sprintf(temp, "%s/.signature", home);
  fd2 = fopen(temp, "r");
  if(fd2!=NULL)
  {
   while(fgets(line, 255, fd2)!=NULL)
   {
    gtk_text_insert (GTK_TEXT (text), NULL, &color, NULL, line, -1);
   }
   fclose(fd2);
  }
 }
 gtk_text_thaw(GTK_TEXT(text));
 close(sockfd);
 return 0;
}

int mirror_server(char *tmp1)
{
 fd_set readfs, newfs;
 int sockfd, max_fd, listen_len, client[100], i=0, j, from_len, len;
 struct timeval timeout;
 struct sockaddr_in listen_addr;
 struct sockaddr_in address;
 struct sockaddr_in from_addr;
 listen_addr.sin_family = AF_INET;
 listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
 listen_addr.sin_port = htons(8500);
 listen_len = sizeof(listen_addr);
 sockfd = socket(AF_INET, SOCK_STREAM, 0);
 if(sockfd<1) { fprintf(stderr, "GXedit: Fatal error: Socket failed\n"); exit(1); }
 if(bind(sockfd, (struct sockaddr *)&listen_addr, listen_len))
 { fprintf(stderr, "GXedit: Fatal error: Binding failed\n"); exit(1); }
 for(j=0;j<100;j++) client[j] = 0;
 while(1)
 {
  timeout.tv_sec = 1;
  timeout.tv_usec = 0;
  FD_ZERO(&readfs);
  FD_SET(sockfd, &readfs);
  max_fd = sockfd;
  memcpy(&newfs, &readfs, sizeof(readfs));
  listen(sockfd, 5);
  select(max_fd+1, &newfs, NULL, NULL, &timeout);
  if(FD_ISSET(sockfd, &newfs))
  {
   client[i] = accept(sockfd, (struct sockaddr *)&address, &len);
   from_len = sizeof(from_addr);
   memset(&from_addr, 0, sizeof(from_addr));
   if(getpeername(client[i], (struct sockaddr *)&from_addr,&from_len) < 0)
   {
    fprintf(stdout, "GXedit: Connection from unknown host\n");
   }
   else
   {
    fprintf(stdout, "GXedit: Connection from %s\n",inet_ntoa(from_addr.sin_addr));
   }
   i++;
  }
  fd = fopen(tmp1, "r");
  if(fd==NULL) exit(1);
  while(fgets(line, 511, fd)!=NULL)
  {
   for(j=0;j<100;j++)
    if(client[j]!=0) write(client[j], line, strlen(line));
  }
  for(j=0;j<100;j++)
   if(client[j]!=0) write(client[j], "\n*** [EOF] ***\n", strlen("\n*** [EOF] ***\n"));
  fclose(fd);
 }
 return 0;
}

int mirror_init()
{
 int len;
 struct sockaddr_in address;
 mirr_cl = socket(AF_INET, SOCK_STREAM, 0);
 address.sin_family = AF_INET;
 address.sin_addr.s_addr = inet_addr(resolve(mirror_remote));
 address.sin_port = htons(8500);
 len = sizeof(address);
 if(connect(mirr_cl, (struct sockaddr *)&address, len)==-1)
 {
  print_debug("Error in connecting to server\n");
  return -1;
 }
 return 0;
}

int mirror_listen(char *tmp1)
{
 fd_set readfs, newfs;
 int max_fd;
 struct timeval timeout;
 int i, result, sockfd;
 char buf[512], inchar;
 sockfd = mirr_cl;
 fd = fopen(tmp1, "w");
 while(1)
 {
  timeout.tv_sec = 20;
  timeout.tv_usec = 0;
  FD_ZERO(&readfs);
  FD_SET(sockfd, &readfs);
  max_fd = sockfd;
  memcpy(&newfs, &readfs, sizeof(readfs));
  if((result=select(max_fd+1, &newfs, NULL, NULL, &timeout))<1)
  {
   mirr_cl = 0;
   return 0;
  }
  bzero(buf, 512);
  for(i=0;(result=read(sockfd,&inchar,1))!='\0';i++)
  {  
   if(result==-1)
   {
    mirr_cl = 0;
    return 0;
   }
   buf[i]=inchar;
   if(inchar=='\n') break;
   if(i==510) break;
  }
  if(!strcasecmp(buf,""))
  {
   mirr_cl = 0;
   return 0;
  }
  if(lindex(buf,0)!=NULL && lindex(buf,1)!=NULL)
  {
   if(!strcasecmp(lindex(buf,0),"***") && !strcasecmp(lindex(buf,1),"[EOF]")) break;
  }
  fputs(buf, fd);
 }
 if(fd!=NULL) fclose(fd);
 return 0;
}
#endif
