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

bt2dc_gui2_prelaunch.c

/* dc_gui2 - a GTK+2 GUI for DCTC
 * Copyright (C) 2002 Eric Prevoteau
 *
 * bt2dc_gui2_prelaunch.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: bt2dc_gui2_prelaunch.c,v 1.2 2004/01/17 15:54:01 ericprev Exp $
*/

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <dirent.h>
#include <sys/param.h>
#include <glib.h>

#ifndef WITHOUT_CURL
#include <curl/curl.h>
#include <gnome.h>


#include "bt2dc_gui2_io.h"

/* ================================================================================================= */
/* ================================================================================================= */
/* ================================================================================================= */
typedef struct
{
      pid_t bt_pid;
      BT_DL_STRUCT *map;      /* mapped file */
} BT_ENTRY;

static GArray *available_bt_entry=NULL;
static GString *bt2dc_gui2_directory=NULL;

/************************************/
/* open and map the given new entry */
/************************************/
static void add_new_entry(const char *filepath, int proc_pid)
{
      int fd;
      BT_ENTRY new_bt;

      fd=open(filepath,O_RDWR);
      if(fd==-1)
      {
            fprintf(stderr,"Fail to open file '%s': %s\n",filepath,strerror(errno));
            return;
      }

      new_bt.bt_pid=proc_pid;
      new_bt.map=mmap(NULL,sizeof(BT_DL_STRUCT),PROT_READ|PROT_WRITE,MAP_SHARED, fd,0);
      if(new_bt.map==MAP_FAILED)
      {
            fprintf(stderr,"Fail to map file '%s': %s\n",filepath,strerror(errno));
            close(fd);
            return;
      }

      close(fd);
      g_array_append_val(available_bt_entry,new_bt);
}

/**********************************************************************************************************/
/* update the content of the bittorrent clist with the content of the directory $HOME/.dc_gui2/bt2dc_gui2 */
/**********************************************************************************************************/
void load_bittorrent_array(void)
{
      DIR *dir;
      struct dirent *obj;
      int base_len;
      GString *fpath;

      dir=opendir(bt2dc_gui2_directory->str);
      if(dir==NULL)
            return;

      fpath=g_string_new(bt2dc_gui2_directory->str);
      base_len=fpath->len;

      while((obj=readdir(dir))!=NULL)
      {
            int proc_pid;
            int ln_obj;

            if(obj->d_name[0]=='.')
                  continue;

            if(strncmp(obj->d_name,"bt_xfer.",8))
                  continue;

            ln_obj=strlen(obj->d_name);
            if(!strcmp(obj->d_name+ln_obj-5,".lock"))       /* avoid .lock files */
                  continue;

            proc_pid=atoi(obj->d_name+8);
            g_string_append(fpath,obj->d_name);
            add_new_entry(fpath->str,proc_pid);
            g_string_truncate(fpath,base_len);
      }
      g_string_free(fpath,TRUE);
      closedir(dir);
}

/***************************************************************/
/* get the current status of all "registered" bittorrent xfers */
/***************************************************************/
static void load_bt_structs(void)
{
      char *path;

      path=getenv("HOME");

      /* bittorrent directory = $HOME/.dc_gui2/bt2dc_gui2/ */
   bt2dc_gui2_directory=g_string_new(NULL);
   g_string_sprintf(bt2dc_gui2_directory,"%s/.dc_gui2/bt2dc_gui2/",(path!=NULL)?path:".");

      available_bt_entry=g_array_new(FALSE,FALSE,sizeof(BT_ENTRY));

      load_bittorrent_array();

      
}

/********************************************************************************************************/
/* search inside the available_bt_entry array an entry with an map->original_url matching the given one */
/********************************************************************************************************/
/* ouput: -1=not found else the pid of the entry (which can be the one of a not running client) */
/************************************************************************************************/
pid_t get_bt_pid_by_bt_url(const char *url)
{
      int i;

      for(i=0;i<available_bt_entry->len;i++)
      {
            BT_ENTRY *be;

            be=&(g_array_index(available_bt_entry,BT_ENTRY,i));
            if((be->map!=NULL)&&(!strcmp(url,be->map->original_url)))
                  return be->bt_pid;
      }
      return -1;
}

/*********************************************************************/
/* check if the given pid is the one of a running bittorrent process */
/*********************************************************************/
/* output: TRUE=dead, FALSE=running */
/************************************/
gboolean is_a_dead_bittorrent(pid_t bt_pid)
{
      int ret=FALSE;          /* process is running by default */
      int fd;

      /* create a path "$HOME/.dc_gui2/bt2dc_gui2/bt_xfer.%d.lock" and try to lock it */
      /* if it is not lockable, the process is running */
      GString *lpath;

      lpath=g_string_new(bt2dc_gui2_directory->str);  /* $HOME/.dc_gui2/bt2dc_gui2 */
      g_string_sprintfa(lpath,"/bt_xfer.%d.lock",bt_pid);
      
      fd=open(lpath->str,O_RDWR);
      if(fd!=-1)
      {     /* ignore errors, assume the process is still running */
            int o;

            o=lockf(fd,F_TEST,1);
            if(o==0)          /* not locked ? */
            {
                  ret=TRUE;
            }
            close(fd);
      }
      else
      {
            fprintf(stderr,"is_a_dead_bittorrent: %s: %s\n",lpath->str,strerror(errno));
      }
      g_string_free(lpath,TRUE);

      return ret;
}

/* ================================================================================================= */
/* ================================================================================================= */
/* ================================================================================================= */
static GString *dl_url=NULL;

/*********************************************************************************************/
/* search for 'Location:' in headers and update dl_url to contain the latest encountered URL */
/*********************************************************************************************/
static size_t header_function(void *ptr, size_t size, size_t nmemb, void *stream)
{
      int ln=size*nmemb;
      char *t;

      if(ln>strlen("Location: ")&&(!strncmp(ptr,"Location: ",strlen("Location: "))))
      {
            g_string_truncate(dl_url,0);
            g_string_insert_len(dl_url,0,((char*)ptr)+strlen("Location: "), ln - strlen("Location: "));
            
            t=strchr(dl_url->str,'\n');
            if(t)
                  g_string_truncate(dl_url,t-dl_url->str);
            
            t=strchr(dl_url->str,'\r');
            if(t)
                  g_string_truncate(dl_url,t-dl_url->str);
      }
      return ln;
}

/*********************************************************************************/
/* use the URL stored in "dl_url" and build a clean URL without HTTP redirection */
/*********************************************************************************/
static void build_clean_url(void)
{
      CURL *curl;
      CURLcode res;

      curl = curl_easy_init();
      if(curl)
      {
            curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_function);
            curl_easy_setopt(curl, CURLOPT_NOBODY, 1);   /* only header */
            curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
            curl_easy_setopt(curl, CURLOPT_URL, dl_url->str);
            res = curl_easy_perform(curl);

            /* always cleanup */
            curl_easy_cleanup(curl);
      }
}

/*********************************************************************************************/
/* this program preforms some basic tests on directory and parse the given URL to remove any */
/* HTTP redirection (original bittorrent seems to have problem with them)                    */
/*********************************************************************************************/
int main(int argc, char **argv)
{
      char *err_msg=NULL;
      GtkWidget *w;
#ifdef ENABLE_NLS
      bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
      bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
      textdomain (GETTEXT_PACKAGE);
#endif

      if(argc!=4)
      {
            printf("Usage: %s <download directory> <done directory> <url>\n",argv[0]);
            exit(1);
      }

      if((access(argv[1],R_OK|W_OK|X_OK)) ||
            (access(argv[2],R_OK|W_OK|X_OK)) )
      {
            err_msg=_("Download or done directory cannot be used.");

            disp_err_msg:
            gnome_program_init (PACKAGE, VERSION, LIBGNOMEUI_MODULE,
                                           argc, argv,
                                           GNOME_PARAM_APP_DATADIR, PACKAGE_DATA_DIR,
                                           NULL);
            w=gnome_error_dialog(err_msg);
            g_signal_connect((gpointer)w,"hide",G_CALLBACK(gtk_main_quit),NULL);
            gtk_main();
            exit(1);
      }
      
      /* scan the URL to process HTTP redirection */
      dl_url=g_string_new(argv[3]);
      build_clean_url();
      
      if(dl_url->len)
      {
            pid_t bt_pid;

            load_bt_structs();
            /* now, we will search for the given URL in the known BT xfer */
            bt_pid=get_bt_pid_by_bt_url(dl_url->str);
            if(bt_pid==-1)
            {
                  /* no known xfer with this URL */
                  chdir(argv[1]);
                  execlp("bt2dc_gui2","bt2dc_gui2", argv[1], argv[2],dl_url->str,NULL);
                  
                  err_msg=_("Fail to start 'bt2dc_gui2' program (start mode).");
                  goto disp_err_msg;
            }
            else
            {
                  /* a registered BT xfer exists with this URL but may be it came from a dead client */
                  if(is_a_dead_bittorrent(bt_pid))
                  {
                        /* yes, the client is dead */
                        char old_bt_pid[32];

                        sprintf(old_bt_pid,"%u",bt_pid);

                        chdir(argv[1]);
                        execlp("bt2dc_gui2","bt2dc_gui2", argv[1], argv[2],dl_url->str,bt_pid,NULL);
                  
                        err_msg=_("Fail to start 'bt2dc_gui2' program (resume mode).");
                        goto disp_err_msg;
                  }
                  else
                  {
                        err_msg=_("A bittorrent already runs with this URL");
                        goto disp_err_msg;
                  }
            }
      }
      exit(0);
}

#else
int main(int argc, char **argv)
{
      fprintf(stderr,"CURL was not available when this program was compiled. Install CURL and recompile.\n");
      exit(1);
}
#endif

Generated by  Doxygen 1.6.0   Back to index