Logo Search packages:      
Sourcecode: dctc version File versions  Download package

main_master.c

/* DCTC - a Direct Connect text clone for Linux
 * Copyright (C) 2001 Eric Prevoteau
 *
 * main_master.c: Copyright (C) Eric Prevoteau <www@a2pb.gotdns.org>
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
/*
$Id: main_master.c,v 1.17 2003/12/28 08:12:38 uid68112 Exp $
*/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/utsname.h>
#include <sys/un.h>
#ifdef __linux__
#include <linux/sem.h>     /* for the value of SEMVMX */
#else
#include <sys/sem.h>
#endif
#include <errno.h>
#include <getopt.h>
#include <string.h>
#include <db.h>
#include <glib.h>
#include <pthread.h>

#include "var.h"
#include "display.h"
#include "action.h"
#include "network.h"
#include "dc_com.h"
#include "key.h"
#include "typical_action.h"
#include "macro.h"
#include "dc_manage.h"
#include "keyboard.h"
#include "mydb.h"
#include "hl_locks.h"
#include "main.h"
#include "gts.h"
#include "user_manage.h"
#include "timed_out_string.h"
#include "sema_master.h"
#include "gdl.h"
#include "uaddr.h"
#include "status.h"
#include "bdb.h"
#include "userinfo.h"
#include "misc.h"
#include "md_db.h"

/*****************************************************/
/* this mutex locks all pointers of user description */
/*****************************************************/
/* nickname, user_desc, cnx_type, email, host_ip_org */
/*****************************************************/
HL_MUTEX user_info=HL_MUTEX_INIT;         /* this is a high level mutex allowing multiple readers or 1 writer */

/*******************************/
/* user description for DC hub */
/*******************************/
char *nickname=NULL;                            /* user nickname */
char *org_nickname=NULL;                  /* user nickname (this is the one given on the command line. */
                                                                  /* it is used when following hub redirection and reconnection) */
char *user_desc=NULL;                     /* user description (can be NULL) */
char *cnx_type=NULL;                            /* connection type. (ex: DSL,Cable,...) */
char cnx_opt=0x1;                /* user status */
                                                                  /* bit 0 always set. */
                                 /* bit 1 ? ==0, user here, ==1, user away */
                                                                  /* bit 2 ? ==0, normal, ==1, is server */
                                                                  /*         according to DC, a server is a client online */
                                                                  /*            for more than 2 hours.                           */
                                                                  /* bit 3 ? ==0, normal, ==1, fast upload */
                                                                  /*         according to DC, a fast upload is a client */
                                                                  /*         having an upload speed greater than 100KB/s. */
char *email=NULL;                               /* user e-mail (can be NULL) */
double sizeof_data=0;                     /* size of the data shared by this client */
double offset_sizeof_data=0;     /* when the client has to return the size of data it shares, this value */
                                 /* is added to the previous one */

int dl_on;                                            /* this flag enables or disables the upload capability */
                                                                  /* if ==1, other users can download from you */
                                                                  /* if ==0, other users cannot download from you */
                                                                  /* this flag doesn't affect free_dl_slot/ttl_dl_slot */
                                                                  /* you still return the original value. If someone want to download, */
                                                                  /* the client will just return a "no more slot" message. */

char *nick_passwd=NULL;                   /* when the hub wants a password. We will use the one here */
                                                                  /* if ==NULL, the client waits one before resuming */

GString *dctc_rating_gs=NULL;       /* this value is not used by DCTC, it is only kept here */

int description_tag_auto=FALSE;     /* if set, the client will automatically attached tag to the user description */

/**************************************/
/* description of the connection type */
/**************************************/
/* (BHF means behind firewall) */
/*******************************/
int behind_fw=0;                          /* !=0, host is behind firewall */
unsigned short com_port;            /* port available, to receive data if not behind fw */
                                                                  /* default value is 412 but it is not very good     */
                                                                  /* because port below 1024 are not allowed for      */
                                                                  /* non-privileged users under Un*x                  */
char *host_ip=NULL;                       /* ip of this host */
char *org_host_ip=NULL;                   /* this is where the command /IP put its content */
                                 /* because the command can provided a FQDN or even a network interface */
                                 /* we cannot load directly host_ip with it */
int dynamic_ip_flag=0;                    /* if ==0, once host_ip has been filled, it is never updated (static IP) */
                                                                  /* else ==1, the host_ip is recomputed each time before connecting the hub */

GString *org_hubip=NULL;      /* strings received from the -g flag */
                                                      /* don't use it except you need the original -g parameter */
GString *hubip=NULL;                /* IP of the hub where we are connected */
unsigned int hub_port=411;    /* port of the hub where we are connected (411 is the default port) */
GString *hubname=NULL;        /* Name of the hub where we are connected (filed when connected) */

unsigned int hub_tos = 0;     /* TOS value to set on hub connections */
unsigned int udp_tos = 0;     /* TOS value to set on udp (search) pakets */
unsigned int dl_tos = 0;      /* TOS value to set on download connections */
unsigned int ul_tos = 0;      /* TOS value to set on upload connections */

unsigned int unode_port=19284;      /* port number for UNODE, it is the current one */
unsigned int wanted_unode_port=19284;     /* port number for UNODE. If you want to change UNODE port, change this value, not the one above */

unsigned int recon_delay=30;  /* number of seconds before the hub connection loss and the /RECON */
unsigned int auto_rebuild_delay=15*60;    /* number of seconds between 2 rebuilds of the shared database */
unsigned int auto_scan_delay=10*60; /* number of seconds between 2 GDL autoscan */

int follow_force_move=0;      /* does the client accept $ForceMove and $OpForceMove */

int max_wait=30;                    /* a task can be queued up to 30 secondes before destruction */
int max_hang=10*60;                 /* a running xfer can received nothing during up to 10 minutes before cancellation */
                                                      /* WARNING: Due to the fact that Direct Connect works with 8KByte bloc, */
                                                      /* a timeout of less than 8 minutes is not recommended else a timeout may occur */
                                                      /* if speed goes beyond 1KB/s. */


int main_sck=-1;                    /* it is the TCP socket connected to the hub */
int cnx_in_progress=0;        /* this flag is set when main_sck is !=-1 but the connect stage is not yet done */

int in_sck=-1;                            /* it is the TCP socket to use as com port */

int srch_sck=-1;                    /* it is the UDP socket used to receive active search result */
                                                      /* it uses the same port number has in_sck */

int keyb_fd=0;                            /* it is the keyboard fd */
                                                      /* must be ==0. If the client loses its term, goes to -1 */

int when_done=0;                    /* when a download is done, ==0, do nothing */
                                                      /* ==1, move the file into the done/ directory */

int with_ddl=0;                     /* enable/disable dDL capability */
int grab_ban_ip=0;                  /* enable/disable IP grabbing of banned users */

int abort_upload_when_user_leaves=0;
                                                      /* abort the remote user upload when a user leaves the hub */

unsigned int max_running_source_per_gdl=10;     /* limit the number of running sources per GDL */
unsigned int disable_gdl_as_when_enough_running=7;    /* disable one GDL's autoscan if enough running sources are available */

int hide_kick=0;              /* hide/show the kick message displayed on the global chat when a user is kicked */

int with_lazy_key_check=0;                /* enable/disable lazy $Key check */

int with_incoming_wake_up=0;        /* enable/disable wakeup of waiting GDL source when a user with a "wanted" nickname enters the hub */
int with_sr_wake_up=0;                    /* enable/disable wakeup of waiting GDL source when a search result with a "wanted" nickname has free slot */

int min_gdl_wake_up_delay=30; /* at least 30 seconds between waking up source of the same user */

int max_dl_per_user=-1;                         /* maximum number of downloads from each user (<=0 :unlimited) */

int gdl_as_port_range[2]={0,0};           /* lower and upper value of GDL autoscan port range */

int min_delay_between_search=0;           /* delay to wait between 2 search queries */

unsigned int sharelist_dl_wo_slot=0;   /* allow downloading of your sharelist by clients even if no slots are available */

unsigned int fake_dcpp_client=0;                /* simulate DC++ tag and key */
GString *fake_dcpp_version=NULL;                /* version of DC++ to simulate */

unsigned int disp_user=1;                             /* disable/enable USER+,USER-, ... and anything related to user change message (1=enable, 0=disable)*/

GPtrArray *client_capabilities=NULL;      /* list of capabilities of the client */

/************************************************************/
/* debug mode. ==0, no debug. !=0, debug mode               */
/* if debug_mode is set, all debug messages will be printed */
/************************************************************/
int debug_mode=0;

int force_quit=0;                   /* if ==1, when /QUIT is called, it doesn't wait end of xfers */

static int user_wants_to_quit=0;    /* this flag is changed when the user hit ctrl-c to quit */

/*******************************************************************/
/* the following vars are used to manage the local AF_UNIX sockets */
/*******************************************************************/
GString *local_dctc_sock_path=NULL;                         /* local name */
int local_sck=-1;                                                             /* main local socket (to accept connection) */
GString *local_dctc_udp_sock_path=NULL;               /* local name */
int local_sck_udp=-1;                                                   /* main local UDP socket (to receive command without being connected (inter DCTC link)) */

GArray *local_client_socket=NULL;                           /* array of all locally connected socket */
G_LOCK_DEFINE(local_client_socket);

GString *dctc_dir=NULL;                                                 /* == $(HOME)/.dctc */

GString *dctc_active_client_file=NULL;

GString *dctc_ls_cache_dir=NULL;                                  /* == dctc_dir/ls_cache/ */

const char *dc_version="1,0091";                                              /* DC version to use */

static GString *local_dctc_user_info_path=NULL;             /* name of the file containing all current user informations */

/*****************************************/
/* information to limit upload bandwidth */
/*****************************************/
int bl_semid=-1;                                            
GString *bl_fname=NULL;

time_t client_start;

G_LOCK_DEFINE(inet_ntoa);           /* inet_ntoa is not thread save, this prevents problem */

/*****************************/
/* display connection status */
/*****************************/
void display_cnx_status(void)
{
      char buf[512];
      int val;

      /* etat de la connexion: bit0: 0= pas de socket, 1= socket vers hub */
      /*                                          bit1: (si bit0!=0) 0= connexion en cours, 2= connection etablie */

      val=(main_sck!=-1)?1:0;
      if(cnx_in_progress==0)
            val+=2;

      sprintf(buf,"%d",val);
      disp_msg(VAR_MSG,NULL,"cnx_status",buf,NULL);
}

/**************************************************************/
/* this function is called when the hub closes its connection */
/*********************************************************************************/
/* if exit_flag==DO_EXIT, the client will not attempt to automatically reconnect */
/*********************************************************************************/
void hub_disconnect(HUBDISC_FLAG exit_flag)
{  
      int i;

      disp_msg(INFO_MSG,"hub_disconnect","in",NULL);

      if(exit_flag==DO_RECONNECT)
      {
            /* close current socket */
            if(main_sck!=-1)
            {
                  close(main_sck);
                  main_sck=-1;
            }

            set_client_status(IS_OFFLINE);
            reset_hub_user_list();        /* else /ULIST will return the old user list */
            display_cnx_status();

            /* reset the nickname to its original value */
            if(nickname!=NULL)
                  free(nickname);
            nickname=strdup(org_nickname);

            add_new_sim_input(0,"/VARS");
            
            return;
      }

      exit_gts();

      if((waiting_action!=NULL)&&(force_quit==0))
      {
            /* wait all thread done */
            char tmp[512];
            
            disp_msg(INFO_MSG,"hub_disconnect","have xfer ?",NULL);
            G_LOCK(waiting_action);
            
            sprintf(tmp,"%d xfer",waiting_action->len);
            disp_msg(INFO_MSG,NULL,tmp,NULL);
            while(waiting_action->len!=0)       /* all thread done ? */
            {
                  G_UNLOCK(waiting_action);
                  sleep(1);
                  G_LOCK(waiting_action);
                  sprintf(tmp,"%d xfer",waiting_action->len);
                  disp_msg(INFO_MSG,NULL,tmp,NULL);

                  if(user_wants_to_quit)        /* wait except if the user wants to leave now */
                        break;
            }
            disp_msg(INFO_MSG,"hub_disconnect","no more xfer",NULL);
      }
      
      disp_msg(VAR_MSG,NULL,"cnx_status","0",NULL);   /* we are disconnected */

      /* close all connections of waiting_action else, threads don't leave properly */
      i=0;
      while(i<waiting_action->len)
      {
            WAIT_ACT *p;

            p=g_ptr_array_index(waiting_action,i);
            if((p!=NULL)&&(p->sock_fd!=-1))
            {
                  shutdown(p->sock_fd,2);
                  close(p->sock_fd);
            }
            i++;
      }

      /* and end */
      del_client_status();
      disp_msg(INFO_MSG,"hub_disconnect","end",NULL);
      if(local_dctc_sock_path!=NULL)
            unlink(local_dctc_sock_path->str);
      if(local_dctc_udp_sock_path!=NULL)
            unlink(local_dctc_udp_sock_path->str);
      uinfo_delete();
      if(local_dctc_user_info_path!=NULL)
            unlink(local_dctc_user_info_path->str);

      /* exit BerkeleyDB lib */
      do_berkeley_exit();

      sleep(1);         /* without this sleep, some of the latest disp_msg doesn't work */
      exit(1);
}

/**************************************************************/
/* xfers queued for a too long time are automatically expired */
/**************************************************************/
static void expire_old_xfer(void)
{
      int i;
      time_t cur_time;
      int force_refresh=0;

      disp_msg(DEBUG_MSG,"expire_old_xfer","in",NULL);
      cur_time=time(NULL);

      G_LOCK(waiting_revcon);
      if((waiting_revcon!=NULL)&&(waiting_revcon->len!=0))
      {
            for(i=waiting_revcon->len-1;i>=0;i--)
            {
                  WAIT_REVCON *ptr;

                  ptr=g_ptr_array_index(waiting_revcon,i);
                  
                  if( (cur_time-ptr->last_touch)> max_wait)
                  {     /* too old ? */

                        /* remove action from the list */
                        g_ptr_array_remove_index(waiting_revcon,i);

                        if(!strncmp(ptr->action_to_do->str,"LS/",3))
                        {
                              uaddr_increase_error_flag(ptr->remote_nick->str);

                              /* we will requeue this xfer inside sim_input */
                              {
                                    GString *sim;

                                    sim=g_string_new("");

                                    g_string_sprintf(sim,"/LS %s", ptr->remote_nick->str);

                                    /* wait 30 seconds before retrying */
                                    if(add_gts_entry(ptr->remote_nick->str,sim->str,30))
                              add_new_sim_input(30,sim->str);     /* fail to queue in the GTS, use sim_input instead */

                                    g_string_free(sim,TRUE);
                              }

                              disp_msg(XFER_LS_UNQUEUED,NULL, ptr->remote_nick->str,ptr->action_to_do->str,NULL);
                        }
                        else if(!strncmp(ptr->action_to_do->str,"XDL|",4))
                        {
                              gchar **fields;

                              uaddr_increase_error_flag(ptr->remote_nick->str);

                              /* notify to GDL the transfer never starts */
                              /* there is always 3 fields, never less, never more */
#ifndef WITH_GLIB2
                              fields=g_strsplit(ptr->action_to_do->str,"|",3);     /* GLIB2 fixed */
#else
                              fields=g_strsplit(ptr->action_to_do->str,"|",3+1);   /* GLIB2 fix */
#endif

                              do_gdl_abort(strtoul(fields[1],NULL,10),fields[2]);
                              g_strfreev(fields);
                              disp_msg(DEBUG_MSG,NULL, "expiring XDL","|lu",(unsigned long)ptr,NULL);
                        }
                        /* free structure */
                        free_action_to_do(ptr,0);
                                          /* don't use 1 here because waiting_revcon is already locked */
                        force_refresh=1;
                  }
            }
      }
      G_UNLOCK(waiting_revcon);

      if(force_refresh)
            disp_msg(REFRESH_MSG,NULL,NULL);

      disp_msg(DEBUG_MSG,"expire_old_xfer","out",NULL);
}

/******************************************************************************/
/* expire running xfer having not received anything since the last 10 minutes */
/******************************************************************************/
static void expire_hanging_xfer(void)
{
      int i;
      time_t cur_time;

      disp_msg(DEBUG_MSG,"expire_hanging_xfer","in",NULL);

      cur_time=time(NULL);

      G_LOCK(waiting_action);
      if((waiting_action!=NULL)&&(waiting_action->len!=0))
      {
            for(i=waiting_action->len-1;i>=0;i--)
            {
                  WAIT_ACT *ptr;

                  ptr=g_ptr_array_index(waiting_action,i);
                  
                  if( (cur_time-ptr->last_touch)> max_hang)
                  {     /* too old ? */
                        disp_msg(DEBUG_MSG,"expire_hanging_xfer","|lu",(unsigned long)ptr,"|lu",(unsigned long)(ptr->thread_id));
                        shutdown(ptr->sock_fd,2);                                   /* simulate a network connection close, like a kill */
                  }
            }
      }
      G_UNLOCK(waiting_action);

      disp_msg(DEBUG_MSG,"expire_hanging_xfer","out",NULL);
}

/**************************************************/
/* check if something is "queued" on the keyboard */
/**************************************************/
static void check_sim_input(int sck)
{
      unsigned int i;
      time_t cur_time;
      GArray *temp_sim;

      disp_msg(DEBUG_MSG,"check_sim_input","in",NULL);

      /* we cannot call keyboard functions if sim_input is locked */
      /* because some of these functions also want to lock it */
      /* to avoid a race problem, we lock sim_input, extract the entries we want, */
      /* unlock it and then call the functions */
      temp_sim=g_array_new(FALSE,FALSE,sizeof(SIM_INPUT));

      G_LOCK(sim_input);

      cur_time=time(NULL);

      i=0;

      while(i<sim_input->len)
      {
            SIM_INPUT *ptr;

            ptr=&(g_array_index(sim_input,SIM_INPUT,i));

            if(ptr->min_start_time>cur_time)
                  i++;                    /* time not yet reached */
            else
            {
                  /* copy the entry in the temp array */
                  temp_sim=g_array_append_val(temp_sim,*ptr);

                  /* and remove it */
                  sim_input=g_array_remove_index(sim_input,i);
                  /* don't add 1 to i, we have remove the current entry, so we already are on the next entry */
            }
      }

      G_UNLOCK(sim_input);

      /* now we will call the function */
      for(i=0;i<temp_sim->len;i++)
      {
            SIM_INPUT *ptr;

            ptr=&(g_array_index(temp_sim,SIM_INPUT,i));

            disp_msg(ASTART_MSG,NULL,ptr->keyb_string->str,NULL);

            keyboard_input(sck,ptr->keyb_string->str);

            /* the g_string is no more useful */
            g_string_free(ptr->keyb_string,TRUE);
      }

      /* g_strings are already freed */
      g_array_free(temp_sim,TRUE);

      disp_msg(DEBUG_MSG,"check_sim_input","out",NULL);
}

/********************************************/
/* someone connect to the local unix socket */
/********************************************/
static void manage_local_socket(int local_sck)
{
      int nw;
      int obuf=128*1024;

      nw=accept(local_sck,NULL,NULL);
      if(nw==-1)
            return;

      if(setsockopt(nw,SOL_SOCKET,SO_SNDBUF,&obuf,sizeof(obuf))<0)
      {
            perror("setsockopt");
      }

      G_LOCK(local_client_socket);
      local_client_socket=g_array_append_val(local_client_socket,nw);
      G_UNLOCK(local_client_socket);
}

/*******************************************************************/
/* read data from unix_socket and send it to the keyboard function */
/*******************************************************************/
static void manage_unix_socket(int main_sck, int sck, int num)
{
      GString *s;
      int n;
      char c;

      if(sck==-1)  /* sometimes, after a network error, it is possible to come here with an invalid socket descriptor */
            return;

      s=g_string_sized_new(512);

      do
      {
            n=read(sck,&c,1);
            if(n!=1)
            {
                  g_string_free(s,TRUE);
                  /*  close sck and remove it from local_client_socket */
                  shutdown(sck,2);
                  close(sck);
                  G_LOCK(local_client_socket);
                  local_client_socket=g_array_remove_index_fast(local_client_socket,num);
                  G_UNLOCK(local_client_socket);
                  return;
            }

            s=g_string_append_c(s,c);
      }while(c!='\n');

      s->str[s->len-1]='\0';        /* replace \n by \0 */

      printf("unix_socket: %s\n",s->str);

      keyboard_input(main_sck,s->str);
      
      g_string_free(s,TRUE);
}

/******************************************************************/
/* read data from UDP socket and send it to the keyboard function */
/******************************************************************/
static void manage_local_udp_socket(int sck)
{
      char buf[8192];
      int ret;

      if(sck==-1)  /* this should never happen but who knows .... */
            return;

      ret=recv(sck,buf,sizeof(buf)-1,MSG_NOSIGNAL);
      if(ret==-1)
      {
            disp_msg(ERR_MSG,"manage_local_udp_socket","recv error",strerror(errno),NULL);
            return;
      }
      if(ret<2)
      {
            return;
      }

      buf[ret]='\0';
      printf("unix_udp_socket: %s\n",buf);

      /* 2 small tests: a valid command always starts with '$' or '~' (conditionnal run) or '*' output messages */
      /*                or '[' (a DCTC output message to relay] */
      /*                it can also be a DCTC command (not used by DCTC itself but can be by UI) */
      /*                and always ends with a '\n' */
      if((buf[0]!='$')&&(buf[0]!='~')&&(buf[0]!='*')&&(buf[0]!='/')&&(buf[0]!='['))
            return;
      if(buf[ret-1]!='\n')
            return;

      keyboard_input(main_sck,buf);
}

/***********************************************/
/* main loop of the program                    */
/* this loop is the running in the main thread */
/***********************************************/
static void main_loop()
{
      int ln;
      int n;
      fd_set rd,wd;
      struct timeval tv;
      int i;
      time_t cur_time;

      while(1)
      {
            cur_time=time(NULL);

            n=-1;

            FD_ZERO(&rd);
            FD_ZERO(&wd);

            if(keyb_fd==0)
            {
                  FD_SET(0,&rd);                /* keyboard input */
                  n=max(n,0);
            }

            if(in_sck!=-1)                /* com port exists ? */
            {
                  FD_SET(in_sck,&rd);
                  n=max(n,in_sck);
            }

            if(srch_sck!=-1)
            {
                  FD_SET(srch_sck,&rd);
                  n=max(n,srch_sck);
            }

            /* local socket */
            if(local_sck!=-1)
            {
                  FD_SET(local_sck,&rd);
                  n=max(n,local_sck);
            }

            if(local_sck_udp!=-1)
            {
                  FD_SET(local_sck_udp,&rd);
                  n=max(n,local_sck_udp);
            }

            /* add unix client socket */
            G_LOCK(local_client_socket);
            for(i=0;i<local_client_socket->len;i++)
            {
                  int hd;

                  hd=g_array_index(local_client_socket,int,i);
                  FD_SET(hd,&rd);
                  n=max(n,hd);
            }
            G_UNLOCK(local_client_socket);

            /* wait at most 1 second */
            tv.tv_sec=1;
            tv.tv_usec=0;

            disp_msg(DEBUG_MSG,"main_loop","1",NULL);

            ln=select(n+1,&rd,&wd,NULL,&tv);
            if(ln>0)
            {
                  if((keyb_fd==0)&&(FD_ISSET(0,&rd)))
                  {     /* something from the keyboard ? */
                        keyboard_input(main_sck,NULL);
                  }
                  else if((in_sck!=-1)&&(FD_ISSET(in_sck,&rd)))
                  {     /* someone wants to connect to this client ? */
                        manage_com_port(in_sck);
                  }
                  else if((srch_sck!=-1)&&(FD_ISSET(srch_sck,&rd)))
                  {
                        manage_srch_port(srch_sck,main_sck);
                  }
                  else if((local_sck!=-1)&&(FD_ISSET(local_sck,&rd)))
                  {
                        /* someone tries to reach the client from unix socket */
                        manage_local_socket(local_sck);
                  }
                  else if((local_sck_udp!=-1)&&(FD_ISSET(local_sck_udp,&rd)))
                  {
                        /* someone tries to reach the client from unix socket */
                        manage_local_udp_socket(local_sck_udp);
                  }
                  else
                  {
                        /* check unix client socket */
                        G_LOCK(local_client_socket);
                        for(i=0;i<local_client_socket->len;i++)
                        {
                              int hd;

                              hd=g_array_index(local_client_socket,int,i);
                              if(FD_ISSET(hd,&rd))
                              {
                                    G_UNLOCK(local_client_socket);
                                    manage_unix_socket(main_sck,hd,i);
                                    G_LOCK(local_client_socket);
                              }
                        }
                        G_UNLOCK(local_client_socket);
                  }
            }
            else if(ln==-1)
            {
                  if(errno!=EINTR)
                        break;
            }
            /* be careful, after calling keyboard_input or get_dc_line_and_process     */
            /* main_sck can become invalid (==-1) and you are deconnected from the hub */
            /* in such case, hub_disconnect has been called and a /RECON should be in  */
            /* the sim_input queue. */

            disp_msg(DEBUG_MSG,"main_loop","2",NULL);
            expire_old_xfer();
            expire_hanging_xfer();
            check_sim_input(main_sck);
            timeout_tos();

            /* if we are connected to the hub */
            if(with_ddl)
            {
                  uaddr_action();
            }

            if(user_wants_to_quit)
            {
                  disp_msg(DEBUG_MSG,NULL,"use /QUIT to quit",NULL);
                  user_wants_to_quit=0;
            }
      }
}

static void catch_sig(int sig)
{
      switch(sig)
      {
            case SIGTERM:
            case SIGQUIT:
            case SIGINT:
                                    user_wants_to_quit=1;
                                    break;
      }
}

/************************************/
/* we don't want to receive SIGPIPE */
/************************************/
static void set_sig(void)
{
      struct sigaction act;
      sigset_t set;

      /* ignore SIGPIPE */
      sigemptyset(&set);
      sigaddset(&set,SIGPIPE);
      sigaddset(&set,SIGHUP);
      sigaddset(&set,SIGCHLD);            /* we want to discard potential children */
      act.sa_handler=SIG_IGN;
      act.sa_mask=set;
      act.sa_flags=SA_RESTART;

      sigaction(SIGPIPE,&act,NULL);
      sigaction(SIGHUP,&act,NULL);
      sigaction(SIGCHLD,&act,NULL);
      sigprocmask(SIG_UNBLOCK,&set,NULL);

      /* and catch some other sig */
      act.sa_handler=catch_sig;
      act.sa_mask=set;
      act.sa_flags=SA_RESTART;      
      sigaction(SIGINT,&act,NULL);
      sigaction(SIGQUIT,&act,NULL);
      sigaction(SIGTERM,&act,NULL);
      sigprocmask(SIG_UNBLOCK,&set,NULL); /* supprime les signaux */
}

/*************************/
/* display program usage */
/*************************/
static void display_usage(char *fname)
{
      fprintf(stderr,"Usage: %s [options]\n"
                                    "Options:\n"
                                    "  -h, --help                      Display this help\n"
                                    "  -n, --nick=NICKNAME             user nickname (default: 'Noname')\n"
                                    "  -d, --dlslot=NUM                number of download slot (default: 3)\n"
                                    "  -s, --share=DIR                 shared directory (default: none)\n"
                                    "  -a, --hostaddr=HOSTIP           IP of the host running this client (mandatory\n"
                                    "                                  if using active mode)\n"
                                    "                                  (default: IP of the first network interface)\n"
                                    "  -p, --port=PORT                 localhost port to accept incoming connection\n"
                                    "                                  (only in active mode)\n"
                                    "                                  (default: 412 (like Direct Connect)). Be\n"
                                    "                                  careful, value below 1024 is only allowed to\n"
                                    "                                  privileged users (root)\n"
                                    "  -f, --firewall                  enable passive mode because host is behind a\n"
                                    "                                  firewall (default: not behind a firewall)\n"
                                    "  -T, --tos=HUB,UDP,DL,UL         TOS-Value to use on hub,udp,download,upload\n"
                                    "                                  connections. Default values are 0.\n"
                                    "  -x, --no_xfer                   Remote users cannot download (same as /DLOFF)\n"
                                    "  -w, --when_done                 When download is done, move the file into\n"
                                    "                                  done/ directory (same as /DONE).\n"
                                    "  -t, --no_tty                    Detach from the tty used by the shell\n"
                                    "                                  starting the program\n"
                                    "  -Z, --socket_dir=DIR            Change the unix socket path (default: ~/.dctc)\n"
                                    "                                  starting (only useful with a GUI)\n"
                                    "  -u, --upload=NUM1,NUM2,NUM3     Bandwidth limit. NUM1 is the number of\n"
                                    "                                  512 bytes per second allowed to be sent\n"
                                    "                                  NUM2 is the number of 512 bytes per second\n"
                                    "                                  allowed to be received. NUM3 is the number\n"
                                    "                                  of 8KBytes bloc per second that can be copied\n"
                                    "                                  when client gathers GDLs parts.\n"
                                    "                                  (default: unlimited [in fact, it is 16MB/s])\n"
                                    "                                  Note: this flag is only taken into account\n"
                                    "                                  if this client creates the bandwidth limit\n"
                                    "                                  semaphore, use /[UDG]BL to change the value\n"
                                    "                                  later\n"
                                    "  -b, --precmd=COMMAND            perform the given command BEFORE connecting to\n"
                                    "                                  the hub. Not all / commands can be used here,\n"
                                    "                                  look at the command list to know which are.\n"
                                    "                                  You can run more than one command by using\n"
                                    "                                  --precmd for each one. When multiple --precmd\n"
                                    "                                  are given, commands are performed in the given\n"
                                    "                                  order.\n"
                  "  -C, --connectproxy=ADDR[:PORT]  address (IP or name) and port of a web proxy\n"
                  "                                  supporting the CONNECT command. The default port\n"
                  "                                  is 8080 if none is provided.\n"
                  "  -S, --socksaddr=ADDR            address (IP or name) of the SOCKS proxy to use\n"
                  "                                  Default: no SOCKS proxy is used\n"
                  "  -P, --socksport=NUM             port of the SOCKS proxy. Default: 1080\n"
                  "                                  Only used if -S used\n"
                  "  -U, --socksuid=STRING           If the SOCKS proxy requires a userID, this is\n"
                  "                                  it. Default: none\n"
                  "  -X, --socksv5                   Enable SOCKS v5 support. Default: if -S is used\n"
                  "                                  SOCKS protocol version 4 is used.\n"
                  "  -K, --sockspass=STRING          If the SOCKS proxy requires a password, use this\n"
                  "                                  flag. Note: if this flag is used, you MUST also\n"
                  "                                  use -U to give a userID.\n"
                                    "\n"
                                    "Be careful, most of the information you provide can't contain the following\n"
                                    "characters because Direct Connect uses them internally: | $\n"
                                    ,fname);
}

/************************************************************/
/* check if the given string contains invalid DC characters */
/************************************************************/
void check_string(char *string)
{
      while(*string!='\0')
      {
            if((*string=='|')||(*string=='$'))
            {
                  fprintf(stderr,"Invalid character ($ or |): %s\n",string);
                  exit(2);
            }
            string++;
      }
}

/****************************************************/
/* rebuild the shared file database periodically    */
/* The rebuilding is performed in a thread to avoid */
/* hanging of the client.                           */
/****************************************************/
static void *periodic_rebuild_db(void *nothing)
{
      while(1)
      {
            sleep(60);
            update_client_ip();
      }
   pthread_exit(NULL);
}

static void start_rebuild_db_thread(void)
{
      static pthread_t thread_id;               /* this variable must exist as long as the thread exist */
      pthread_attr_t thread_attr;

      pthread_attr_init (&thread_attr);
      pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
      if(pthread_create(&thread_id,&thread_attr, (void*)periodic_rebuild_db,NULL)!=0)
      {
            disp_msg(ERR_MSG,"start_rebuild_db_thread","pthread_create failed","Periodic rebuilding of shared file database disabled",NULL);
      }
      pthread_attr_destroy(&thread_attr);
}

/* beginning of the code */
int main(int argc,char **argv)
{
      static struct option optab[]= {
                                                                        {"help",no_argument,NULL,'h'},                        /* get help */
                                                                        {"nick",required_argument,NULL,'n'},            /* nickname */
                                                                        {"dlslot",required_argument,NULL,'d'},          /* number of download slot */
                                                                        {"hostip",required_argument,NULL,'a'},          /* IP of the host running client */
                                                                        {"port",required_argument,NULL,'p'},            /* port to use to accept connection */
                                                                        {"firewall",no_argument,NULL,'f'},              /* host behind firewall ? */
                                                                        {"tos",required_argument,NULL,'T'},             /* tos for connections */
                                                                        {"no_xfer",no_argument,NULL,'x'},               /* disable remote xfer ? */
                                                                        {"when_done",no_argument,NULL,'w'},             /* move file when download over */
                                                                        {"no_tty",no_argument,NULL,'t'},                      /* detach from start shell tty */
                                                                        {"upload",required_argument,NULL,'u'},          /* upload bandwidth limit */
                                                                        {"precmd",required_argument,NULL,'b'},          /* send a command to execute before hub connection */
                                                                        {"socket_dir",required_argument,NULL,'Z'},/* set the unix socket path */
                                                                        {"connectproxy",required_argument,NULL,'C'}, /* set the address and port of a web proxy supporting the CONNECT command to use */
                                                                        {"socksaddr",required_argument,NULL,'S'}, /* set the address of the socks proxy to use */
                                                                        {"socksport",required_argument,NULL,'P'}, /* set the port of the socks proxy to use */
                                                                        {"socksuid",required_argument,NULL,'U'},  /* set the userID to use with the socks proxy */
                                                                        {"sockspass",required_argument,NULL,'K'}, /* set the user password to use with the socks proxy */
                                                                        {"socksv5",no_argument,NULL,'X'},               /* use SOCKS v5 instead of SOCKS v4 */

                                                                        {NULL,0,NULL,'\0'}                              /* last option */
                                                                  };
      static const char *short_opt="hn:d:a:p:fT:xwtu:b:Z:C:S:P:U:XK:";
                                                            
      int ch;
      int detach_from_tty=0;
      int wait_lnk=0;
      int spd_limit=SEMVMX;
      int dl_spd_limit=SEMVMX;
      int gath_spd_limit=SEMVMX;
      int ttl_dl_slot;
      int iamthemaster=0;

      char *socket_dir;

      /* the 2 sh_* are used to stored -s directories */
      GStringChunk *sh_gsc;
      GPtrArray *sh_gpa;

      /* the 2 pre_* are used to stored --precmd commands */
      GStringChunk *pre_gsc;
      GPtrArray *pre_gpa;

      char *virtual_share_path=NULL;

      disp_msg(INFO_MSG,NULL,"Direct Connect Text Client v" VERSION ,NULL);

      if(argc==1)
      {
            display_usage(argv[0]);
            exit(0);
      }

      /* initialize random number generator else all clients will generate the same digit at the end of the nick */
      srand(time(NULL));

      /* set default values */
      nickname=strdup("Noname");
      user_desc=NULL;
      cnx_type=strdup("Cable");
      email=NULL;
      sizeof_data=0;
      offset_sizeof_data=0;
      ttl_dl_slot=3;
      dl_on=1;

      /* to be able to accept connection, we must set few values */
      behind_fw=0;
      com_port=412;

      socket_dir=NULL;

      sh_gsc=g_string_chunk_new(128);
      sh_gpa=g_ptr_array_new();

      pre_gsc=g_string_chunk_new(128);
      pre_gpa=g_ptr_array_new();

      while((ch=getopt_long(argc,argv,short_opt,optab,NULL))!=EOF)
      {
            switch(ch)
            {
                  case 'h':   display_usage(argv[0]);
                                          exit(0);

                  case 'n':   if(nickname!=NULL)
                                                free(nickname);
                                          nickname=strdup(optarg);
                                          check_string(nickname);
                                          break;

                  case 'd':   ttl_dl_slot=atoi(optarg);
                                          if(ttl_dl_slot<0)
                                                ttl_dl_slot=0;
                                          break;

                  case 'a':   if(org_host_ip!=NULL)
                                                free(org_host_ip);
                                          org_host_ip=strdup(optarg);
                                          break;

                  case 'p':   com_port=strtoul(optarg,NULL,10);
                                          if(com_port==0)
                                          {
                                                fprintf(stderr,"You can't use 0 as com port.\n");
                                                exit(1);
                                          }
                                          break;

                  case 'f':   behind_fw=1;
                                          break;
                  case 'T':   sscanf(optarg,"%d,%d,%d,%d",&hub_tos,&udp_tos,&dl_tos,&ul_tos);
                                          break;
                  case 'x':   dl_on=0;
                                          break;

                  case 'w':   when_done=1;
                                          break;

                  case 't':   detach_from_tty=1;
                                          break;

                  case 'l':   wait_lnk=1;
                                          break;

                  case 'u':   sscanf(optarg,"%d,%d,%d",&spd_limit,&dl_spd_limit,&gath_spd_limit);
                                          if((spd_limit<0)||(spd_limit>SEMVMX))
                                                spd_limit=SEMVMX;
                                          if((dl_spd_limit<0)||(dl_spd_limit>SEMVMX))
                                                dl_spd_limit=SEMVMX;
                                          if((gath_spd_limit<0)||(gath_spd_limit>SEMVMX))
                                                gath_spd_limit=SEMVMX;
                                          break;

                  case 'b':   g_ptr_array_add(pre_gpa,g_string_chunk_insert(pre_gsc,optarg));
                                          break;

                  case 'Z':   /* unix socket path */
                                          socket_dir=strdup(optarg);
                                          break;

                  case 'C':   /* web proxy address */
                                          if(web_proxy_address!=NULL)
                                                free(web_proxy_address);
                                          if(strlen(optarg)==0)
                                                web_proxy_address=NULL;
                                          else
                                                web_proxy_address=strdup(optarg);
                                          break;

                  case 'S':   /* SOCKS address */
                                          if(socks_ip!=NULL)
                                                free(socks_ip);
                                          if(strlen(optarg)==0)
                                                socks_ip=NULL;
                                          else
                                                socks_ip=strdup(optarg);
                                          break;

                  case 'P':   /* SOCKS port */
                                          socks_port=strtoul(optarg,NULL,10);
                                          if((socks_port==0)||(socks_port>65534))
                                          {
                                                socks_port=1080;
                                                disp_msg(ERR_MSG,NULL,"SOCKS port is invalid. Must be >0 and <65535, have:",optarg,"SOCKS port forced to 1080",NULL);
                                          }
                                          break;

                  case 'U':   /* SOCKS user ID */
                                          if(socks_name!=NULL)
                                                free(socks_name);
                                          socks_name=strdup(optarg);
                                          break;

                  case 'K':   /* SOCKS user password */
                                          if(socks_pass!=NULL)
                                                free(socks_pass);
                                          socks_pass=strdup(optarg);
                                          break;

                  case 'X':   /* SOCKS v5 enabled */
                                          use_socks_v5=TRUE;
                                          break;

                  default:
                                          fprintf(stderr,"Unknown option: %c (ignored)\n",ch);
                                          break;
            }
      }

      org_nickname=strdup(nickname);
      hubip=g_string_new("dummy_client");
      org_hubip=g_string_new(hubip->str);
      hubname=g_string_new("dummy_client - MASTER");
      /* main_sck will always be -1 */

      /* if SOCKS is used, force passive mode */
      if(socks_ip!=NULL)
            behind_fw=1;

      /* check if hub address seems to be ok */
      if( (hubip==NULL) || (hubip->len<4) )
      {
            fprintf(stderr,"You must provide a valid hub address\n");
            exit(1);
      }

      /* no IP ? set it to the first network interface IP */
      if(host_ip==NULL)
      {
            GString *hip;

            hip=get_default_host_ip(org_host_ip,dynamic_ip_flag);
            if(hip==NULL)
            {
                  fprintf(stderr,"Unable to obtain localhost IP.\n");
                  exit(1);
            }
            host_ip=hip->str;

            g_string_free(hip,FALSE);
            fprintf(stderr,"Using %s as localhost IP.\n",host_ip);
      }

      g_thread_init(NULL);                      /* initialize glib thread functions */

      client_start=time(NULL);

      /* ignore some signals */
      set_sig();

      if(detach_from_tty)
      {
            int a;

            a=open("/dev/null",O_WRONLY);
            if(a==-1)
                  exit(fprintf(stderr,"unable to open /dev/null\n"));

            dup2(a,0);
            dup2(a,1);
            dup2(a,2);
            close(a);
      
            keyb_fd=-1;
      }

      /* allocated running task array and queued task array */
      waiting_action=g_ptr_array_new();
      waiting_revcon=g_ptr_array_new();
      sim_input=g_array_new(FALSE,FALSE,sizeof(SIM_INPUT));

      /* run precmd commands */
      {
            int i;
            gboolean has_capab=FALSE;

            for(i=0;i<pre_gpa->len;i++)
            {
                  if(!strncmp(g_ptr_array_index(pre_gpa,i),"/CAPAB ",strlen("/CAPAB ")))
                        has_capab=TRUE;
                  process_precmd_command(g_ptr_array_index(pre_gpa,i));
            }
            g_ptr_array_free(pre_gpa,TRUE);
            g_string_chunk_free(pre_gsc);

            if(has_capab==FALSE)
            {
                  disp_msg(ERR_MSG,"","No client capabilities set: default to '/CAPAB MD4x'.",NULL);
                  process_precmd_command("/CAPAB MD4x");
            }
      }

      set_tos_sock(main_sck,hub_tos);
      cnx_in_progress=0;            /* don't set CNX in progress, it prevents emission on com socket */

      /* create com port, even if behind firewall else we cannot return search result */
      {
            do
            {
                  do
                  {
                        in_sck=_x_tcp(com_port);
                        if(in_sck==-1)
                              com_port++;
                  } while(in_sck==-1);

                  listen(in_sck,64);
      
                  srch_sck=_x_udp(com_port,0);
                  if(srch_sck==-1)
                  {
                        close(in_sck);
                        com_port++;
                  }
            }while(srch_sck==-1);

            set_tos_sock(srch_sck,udp_tos);
            listen(in_sck,64);
      }

      /* create array for local client sockets */
      local_client_socket=g_array_new(FALSE,FALSE,sizeof(int));

      /* create local unix socket */
      {
            char *path;
            struct stat st;

            local_dctc_sock_path=g_string_new(NULL);

            if (socket_dir) {
                  g_string_sprintf(local_dctc_sock_path,"%s",socket_dir);
                  free(socket_dir);
            } else {
                  path=getenv("HOME");
                  g_string_sprintf(local_dctc_sock_path,"%s/.dctc",(path!=NULL)?path:".");
            }

            if(stat(local_dctc_sock_path->str,&st))
            {
                  if(mkdir(local_dctc_sock_path->str,0777))
                  {
                        perror("mkdir");
                        exit(1);
                  }
            }
            else
            {
                  if(access(local_dctc_sock_path->str,R_OK|W_OK|X_OK))
                  {
                        disp_msg(ERR_MSG,"","access to ",local_dctc_sock_path->str," ",strerror(errno),NULL);
                        exit(1);
                  }
            }

            dctc_dir=g_string_new(local_dctc_sock_path->str);

            local_dctc_sock_path=g_string_append(local_dctc_sock_path,"/running");
            if(stat(local_dctc_sock_path->str,&st))
            {
                  if(mkdir(local_dctc_sock_path->str,0777))
                  {
                        perror("mkdir");
                        exit(1);
                  }
            }
            else
            {
                  if(access(local_dctc_sock_path->str,R_OK|W_OK|X_OK))
                  {
                        disp_msg(ERR_MSG,"","access to ",local_dctc_sock_path->str," ",strerror(errno),NULL);
                        exit(1);
                  }
            }

            /* initialize the md database */
            {
                  gchar *dctc_md_db=g_strconcat(dctc_dir->str,"/md_db",NULL);
                  if(init_md_db(dctc_md_db))
                  {
                        disp_msg(ERR_MSG,"","fail to create MD database file (",dctc_md_db,").",NULL);
                        exit(1);
                  }
                  g_free(dctc_md_db);
            }

            g_string_sprintfa(local_dctc_sock_path,"/dctc-%08X-%s",getpid(),org_hubip->str);

            /* create local TCP socket (dctc<=>ui com) */
            local_sck=socket(AF_UNIX,SOCK_STREAM,0);
            if(local_sck==-1)
            {
                  perror("local_sck - socket");
                  exit(1);
            }
            
            {
                  struct sockaddr_un name;

                  name.sun_family=AF_UNIX;
                  strcpy(name.sun_path,local_dctc_sock_path->str);
                  if(bind(local_sck,(void *)&name,sizeof(struct sockaddr_un)))
                  {
                        perror("local_sck - bind");
                        exit(1);
                  }

                  listen(local_sck,3);
            }

            /* create local UDP socket (dctc<=>dctc com) */
            local_dctc_udp_sock_path=g_string_new(local_dctc_sock_path->str);
            local_dctc_udp_sock_path=g_string_append(local_dctc_udp_sock_path,".udp");

            local_sck_udp=socket(AF_UNIX,SOCK_DGRAM,0);
            if(local_sck_udp==-1)
            {
                  perror("local_sck_udp - socket");
                  exit(1);
            }
            
            {
                  struct sockaddr_un name;

                  name.sun_family=AF_UNIX;
                  strcpy(name.sun_path,local_dctc_udp_sock_path->str);
                  if(bind(local_sck_udp,(void *)&name,sizeof(struct sockaddr_un)))
                  {
                        perror("local_sck_udp - bind");
                        exit(1);
                  }
            }

            /* if necessary, wait for someone to connect on the TCP socket */
            if(wait_lnk)
            {
                  manage_local_socket(local_sck);
            }
      }

      /* create name for user info LMP */
      local_dctc_user_info_path=g_string_new(local_dctc_sock_path->str);
      local_dctc_user_info_path=g_string_append(local_dctc_user_info_path,".userinfo");
      uinfo_create(local_dctc_user_info_path->str);

      last_cmd_time=time(NULL);
      display_cnx_status();

      init_gts();
      init_uaddr();
   reset_hub_user_list();


      /* perform bandwidth limitation semaphore init and choose a master */
      {
            struct utsname unm;

            uname(&unm);

            bl_fname=g_string_new(dctc_dir->str);
            bl_fname=g_string_append_c(bl_fname,'/');
            bl_fname=g_string_append(bl_fname,unm.nodename);
            g_string_sprintfa(bl_fname,".%u",SEMA_ARRAY_LEN);
            if(do_sema_init(bl_fname->str,&bl_semid,spd_limit, dl_spd_limit, gath_spd_limit,ttl_dl_slot))
            {
                  fprintf(stderr,"Unable to initialize Bandwidth limitation semaphore.\n");
                  exit(1);
            }
      }
      iamthemaster=check_sema_master(bl_semid);
      if(iamthemaster)
      {
            gchar *master_path;

            master_path=g_strconcat(dctc_dir->str,"/running/master",NULL);
            unlink(master_path);
            symlink(local_dctc_sock_path->str,master_path);
            g_free(master_path);
      }

      /* initialize BerkeleyDB lib */
      do_berkeley_init();

      dctc_active_client_file=g_string_new(dctc_dir->str);
      dctc_active_client_file=g_string_append(dctc_active_client_file,"/gstatus");

      dctc_ls_cache_dir=g_string_new(dctc_dir->str);                                /* == dctc_dir/ls_cache */
      dctc_ls_cache_dir=g_string_append(dctc_ls_cache_dir,"/ls_cache");
      {
            struct stat st;
            if(stat(dctc_ls_cache_dir->str,&st))
            {
                  if(mkdir(dctc_ls_cache_dir->str,0777))
                  {
                        perror("mkdir");
                        exit(1);
                  }
            }
      }
      dctc_ls_cache_dir=g_string_append_c(dctc_ls_cache_dir,'/');

      /* its time to add the shared directories to the list of shared directories */
      {
            int i;
            float cur_pos=0;
            float step=100.0/(sh_gpa->len);

            if(virtual_share_path!=NULL)
            {
                  set_vshare_directory(virtual_share_path);
                  free(virtual_share_path);
            }

            disp_msg(PROGRESS_BAR,"","init_share","0","Initialize shared file database",NULL);
            
            for(i=0;i<sh_gpa->len;i++)
            {
                  gchar *p;

                  p=g_ptr_array_index(sh_gpa,i);
                  if(p!=NULL)
                  {
                        char tmp_str[512];
                        sprintf(tmp_str,"%.2f",cur_pos);
                        disp_msg(PROGRESS_BAR,"","init_share",tmp_str,"Initialize shared file database",p,NULL);
                        add_shared_directory(p);
                  }
                  cur_pos+=step;
            }
            disp_msg(PROGRESS_BAR,"","init_share","100","Shared file database Initialized",NULL);

            /* now, we can free no more useful structures */
            g_ptr_array_free(sh_gpa,TRUE);
            g_string_chunk_free(sh_gsc);
      }

#if 0
      set_client_status(IS_ONLINE);
#else
      hub_disconnect(DO_RECONNECT);
#endif
      start_rebuild_db_thread();

      start_gdl_thread();

      /* say hello to other local DCTCs */
      send_dc_line_to_dctc_link_direct(NULL,"/HELLODCTC");

      if(iamthemaster)
            main_loop();

      /* despite of what it looks like, everything below this comment is never used */
      exit_gts();
      exit_uaddr();

      /* exit BerkeleyDB lib */
      do_berkeley_exit();

      /* close internet socket */
      close(main_sck);
      main_sck=-1;

      /* close unix sockets */
      close(local_sck);
      local_sck=-1;
      close(local_sck_udp);
      local_sck_udp=-1;

      G_LOCK(local_client_socket);
      while(local_client_socket->len!=0)
      {
            int hd;

            hd=g_array_index(local_client_socket,int,0);
            shutdown(hd,2);
            close(hd);
            local_client_socket=g_array_remove_index_fast(local_client_socket,0);
      }
      G_UNLOCK(local_client_socket);
      
      unlink(local_dctc_sock_path->str);
      unlink(local_dctc_udp_sock_path->str);
      uinfo_delete();
      unlink(local_dctc_user_info_path->str);

      disp_msg(INFO_MSG,"main","end of client",NULL);
      return 0;
}


Generated by  Doxygen 1.6.0   Back to index