|Portada|Blog|Space|

[Índice] > Usando DCC y conexión en IPv6

Dado que todavía no es muy común que los usuarios comunes tengan IPv6, y
dado que yo uso IPv6 tunelizado detrás de una conexión IPv4 con
dirección variable, es que tuve que configurar mi cliente de IRC para
que las conexiones por DCC las escuchara en IPv4 y en una dirección que
resuelva antes de mandar la petición. A lo que no existe tal parámetro
de configuración, me tuve que hacer un módulo que justamente haga esto.

Nota: Leyendo el código se darán cuenta que sólo funciona en xchat. Si
no desean el diálogo de gtk, pueden en el borrar la opción -DHAS_GTK=1
en el Makefile.

Aquí el código del Makefile:

ddcc.so:ddcc.c Makefile
        $(CC) -Wall -shared -fPIC -I/usr/include/xchat -DHAS_GTK=1 $< -o $@ `pkg-config --libs --cflags gtk+-2.0`

y aquí el del ddcc.c:

#include <netdb.h>
#include <netinet/in.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>

#if HAS_GTK
# include <gtk/gtk.h>
#endif

#include "xchat-plugin.h"

static xchat_plugin * ph;
static char * cfg_hostname = NULL;
static char * filename = NULL;

static int ddcc_command_dcc(char * word[], char * word_eol[], void * user_data);
static int ddcc_command_ddcc(char * word[], char * word_eol[], void * user_data);
static void ddcc_update_address(void);
static void ddcc_load_config(void);
static void ddcc_set_hostname(const char * hostname);

#if HAS_GTK
GtkWidget *dialog, *entry;
static void ddcc_dialog(void);
static void ddcc_dialog_callback(GtkDialog *dialog, gint response_id, void*data);
#endif

int xchat_plugin_init(xchat_plugin * plugin_handle,
    char ** plugin_name, char ** plugin_desc, char ** plugin_version,
    char * arg) {

  ph = plugin_handle;

  *plugin_name = "dDCC";
  *plugin_desc = "Own dcc address modifier";
  *plugin_version = "1";

  xchat_hook_command(ph, "DCC", XCHAT_PRI_HIGH, ddcc_command_dcc, NULL, NULL);
  xchat_hook_command(ph, "DDCC", XCHAT_PRI_HIGH, ddcc_command_ddcc, NULL, NULL);

  xchat_print(ph, "dDCC loaded\n");

  {
    char tmp[PATH_MAX];
    char * home = getenv("HOME");
    int len = strlen(home);
    if (len>=PATH_MAX-50) return 0;
    strcpy(tmp, home);
    strcpy(tmp+len, "/.xchat2/ddcc.cfg");
    filename = malloc(sizeof(tmp)+1);
    strcpy(filename, tmp);
  }
  ddcc_load_config();

#if HAS_GTK
  if (!cfg_hostname)
    ddcc_dialog();
#endif

  xchat_print(ph, "You can modify the address at which your DCC files will be sent\n");
  xchat_print(ph, "using: /DDCC SET_HOSTNAME <Your_Hostname> \n");

  return 1;
}

int xchat_plugin_deinit(void) {
  if (filename)
    free(filename);
  if (cfg_hostname)
    free(cfg_hostname);
  xchat_print(ph, "dDCC unloaded\n");
  return 1;
}

int ddcc_command_ddcc(char * word[], char * word_eol[], void * user_data) {
  if (!strcasecmp(word[2], "set_hostname"))
    ddcc_set_hostname(word[3]);
  return XCHAT_EAT_XCHAT;
}

int ddcc_command_dcc(char * word[], char * word_eol[], void * user_data) {
  if (!strcasecmp(word[2], "send") ||
      !strcasecmp(word[2], "chat")) {
    ddcc_update_address();
  }
  return XCHAT_EAT_NONE;
}

static void ddcc_update_address(void) {
  int err;
  unsigned char * haddr;
  struct addrinfo *res = NULL, hints = {
    .ai_family = AF_INET,
    .ai_protocol = PF_INET,
  };
  if (!cfg_hostname)
    return;

  if ((err = getaddrinfo(cfg_hostname, NULL, &hints, &res)) || !res) {
    xchat_printf(ph, "Warning, could not resolve hostname: %s\n", cfg_hostname);
    xchat_printf(ph, "Error reported: %s\n", gai_strerror(err));
    return;
  }
  haddr = (unsigned char *) &(((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr);
  freeaddrinfo(res);

  // Always big endian.
  xchat_commandf(ph, "set dcc_ip %d.%d.%d.%d",
        haddr[0], haddr[1], haddr[2], haddr[3]);
  //xchat_print(ph, "New IP set in dcc_ip\n");
}

static void ddcc_load_config(void) {
  char buffer[1000];
  FILE * f = fopen(filename, "r");
  if (!f)
    return;
  if (fgets(buffer, 1000, f)) {
    char * nl = strchr(buffer, '\n');
    if (nl)
      *nl = 0;
    ddcc_set_hostname(buffer);
  }
  fclose(f);
}

static void ddcc_set_hostname(const char * hostname) {
  if (cfg_hostname)
    free(cfg_hostname);
  if (!hostname || !*hostname)
    cfg_hostname = NULL;
  else {
    cfg_hostname = malloc(sizeof(hostname) + 1);
    strcpy(cfg_hostname, hostname);
  }
  FILE * f = fopen(filename, "w");
  if (!f) {
    xchat_printf(ph, "Warning: dDCC could not save config to: %s\n", filename);
    return;
  }
  fprintf(f, "%s\n", hostname);
  fclose(f);
}

#if HAS_GTK
static void ddcc_dialog(void) {
  dialog = gtk_dialog_new_with_buttons("Ingrese hostname", NULL,
        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
        GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
        GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
        NULL);
  GtkWidget * label = gtk_label_new(
        "Ingrese aquí el dominio que identifica a su computadora.\n"
        "Las conexiones DCC serán dirigidas a este dominio.");
  entry = gtk_entry_new();
  if (cfg_hostname)
    gtk_entry_set_text(GTK_ENTRY(entry), cfg_hostname);
  g_signal_connect_swapped(dialog,
        "response",
        G_CALLBACK(ddcc_dialog_callback),
        dialog);
  gtk_container_set_border_width(GTK_CONTAINER(dialog), 10);
  gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog)->vbox), 10);
  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), entry);
  gtk_widget_show_all(dialog);
}

static void ddcc_dialog_callback(GtkDialog *dialog, gint response_id, void * data) {
  if (response_id == GTK_RESPONSE_ACCEPT) {
    const char * hostname = gtk_entry_get_text(GTK_ENTRY(entry));
    ddcc_set_hostname(hostname);
  }
  gtk_widget_destroy(GTK_WIDGET(dialog));
}
#endif


---------
Los documentos en este sitio se encuentran licenciados bajo la GFDL.
Ver comentarios: [Hay i comentarios]
Para agregar un comentario: agregue a la URL: ?do=show_comment_form (explicación)