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

net.c

/*  Gaby
 *  Copyright (C) 1998-1999 Frederic Peters
 *
 *  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.
 */

#include <gaby.h>
#include <tables.h>
#include <f_config.h>
#include <gtk_config_dlg.h>

/* actions: mail phone dtmfdial */

/*#define DEFAULT_EMAIL_CMD         "xterm -e mutt \"$e\""*/
#define DEFAULT_EMAIL_CMD           ""
#define DEFAULT_PHONE_CMD           "dtmfdial $p"
#define DEFAULT_COUNTRY_CODE        ""
#define DEFAULT_AREA_CODE           ""
#define DEFAULT_LONG_DISTANCE_CODE  "0"
#define DEFAULT_INTERNATIONAL_CODE  "00"

mstatic void net_mail (struct action_param fields[3], int *dec);
mstatic void net_phone (struct action_param field[1], int *dec);
#ifdef HAVE_LINUX_SOUNDCARD_H
mstatic void net_dtmfdial(struct action_param param[1], int *dec);
#endif

#ifndef FOLLOW_MIGUEL
void get_function_by_name(gchar *name, action *a)
{
#ifdef DEBUG_GABY
      debug_print("[net:get_function_by_name] --\n");
#endif
      a->function = NULL;
      if ( strcmp(name, "mail") == 0 )
            a->function = net_mail;
      if ( strcmp(name, "phone") == 0 )
            a->function = net_phone;
#ifdef HAVE_LINUX_SOUNDCARD_H
      if ( strcmp(name, "dtmfdial") == 0 )
            a->function = net_dtmfdial;
#endif

}
#endif /* ! FOLLOW_MIGUEL */

/**
 * mail
 * @param1: first name
 * @param2: last name
 * @param3: e-mail address
 *
 * Description:
 * Launch a program to write an e-mail to the given person at the given
 * address.
 */
mstatic void net_mail (struct action_param param[3], int *dec)
{
/*
 * fields[0] : 'First Name'
 * fields[1] : 'Last Name'
 * fields[2] : 'E-Mail'
 */
      union data fields[3];
      GString *st = g_string_new("");
      gchar *str;
      gchar *s;
      char cmd[1024];
      
      memcpy(&fields[0], &param[0].val, sizeof(union data));
      memcpy(&fields[1], &param[1].val, sizeof(union data));
      memcpy(&fields[2], &param[2].val, sizeof(union data));
      
      /* WISHLIST: different sorts of e-mail address formatting */
      if ( fields[0].str != NULL && fields[0].str->str[0] != 0 ) {
            st = g_string_append(st, fields[0].str->str);
            st = g_string_append(st, " ");
      }

      if ( fields[1].str != NULL && fields[1].str->str[0] != 0 ) {
            st = g_string_append(st, fields[1].str->str);
            st = g_string_append(st, " ");
      }

      if ( fields[2].str == NULL || fields[2].str->str[0] == 0 ) {
            g_string_free(st, 1);
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(_("Unable to guess email address."));
            (*dec)--;
            return;
      }

      st = g_string_append(st, "<");
      st = g_string_append(st, fields[2].str->str);
      st = g_string_append(st, ">");

#ifdef DEBUG_GABY
      debug_print("[action:mailto] I'll mail %s\n", st->str);
#endif
      
      str = get_config_str("actions", "net", "cmd_email", DEFAULT_EMAIL_CMD);
      if ( strlen(str) == 0 ) {
            GtkWidget *a = configure_dialog(_("Net"));
            if ( a ) gtk_widget_show(a);
            gaby_message = g_strdup(
                  _("The command to send mails was not specified.\n"
                    "You should enter it in the Preferences dialog."));
            gaby_errno = CUSTOM_WARNING;
            gaby_perror_in_a_box();
            (*dec)--;
            return;
      }

#ifdef DEBUG_GABY
      debug_print("[action:mailto] using %s\n", str);
#endif
      if ( strstr(str, "$e") == NULL ) {
            sprintf(cmd,_("The command for sending e-mail (%s) does not "
                       "have \"$e\" in it, which is the way to tell it "
                       "what is the address you want to mail to."), str);
            g_free(str);
            g_string_free(st, 1);
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(cmd);
            (*dec)--;
            return;
      }
      
      s = strstr(str, "$e"); s[0] = 0; s[1] = 0;

      st = g_string_prepend(st, str);
      st = g_string_append(st, str+strlen(str)+2);
      
      g_free(str);
      strcpy(cmd, st->str);
      g_string_free(st, 1);
#ifdef DEBUG_GABY
      debug_print("exec %s\n", cmd);
#endif
      
      (*dec)--;

      if (fork()) return;
      setsid();
      if(execl("/bin/sh","sh","-c", cmd, NULL)==-1){exit(100);}
      exit(0);
      
}

static gboolean create_phone_number(gchar *res, gchar *str)
{
      char *country_code, *area_code, *ld_code, *i18n_code;
      char *cur_res;
      int i;
      
      /*
       * there is not a rfc822-like for phone numbers and I'm not even sure
       * there is a standardized way to write them. I'll try to guess
       * correctly whatever the number looks like but this might not be
       * successfull in every cases. Anyway if you have problems with the way
       * you write them tell me and I'll do my best to make it work with you.
       * 
       * Well let's come to numbers :
       *  iii : country code, this may be 1, 2 or 3 numbers
       *  ac  : area code
       *  xx  : others numbers
       *  lc  : long distance call prefix
       *  ic  : international call prefix
       *
       * and I support the following :
       *           xxx.xx.xx (there may be more numbers)
       *           xxx xx xx
       *      lcac-xxx.xx.xx  where the dots may be spaces
       *      lcac/xxx.xx.xx  where (same)
       *   +iii-ac-xxx.xx.xx
       *   +iii(ac)xxx.xx.xx
       *  iciii-ac-xxx.xx.xx
       * 
       * and may support others if lucky.
       */

      /* and now the real stuff ... */
      
      i18n_code = get_config_str("actions", "net", "international_code", 
                                    DEFAULT_INTERNATIONAL_CODE );
      cur_res = res;
      if ( str[0] == '+' ) {
            strcpy(res, i18n_code);
            cur_res = res + strlen(res);
      }
      for ( i=0; i<strlen(str); i++ ) {
            if ( isdigit((int)(str[i])) ) {
                  *cur_res = str[i];
                  cur_res++;
            }
      }
      *cur_res = 0;
      
      ld_code = get_config_str("actions", "net","long_distance_code", 
                                    DEFAULT_LONG_DISTANCE_CODE );
      
      if ( strncmp(res, i18n_code, strlen(i18n_code)) == 0) {
            country_code = get_config_str("actions", "net", 
                        "country_code", DEFAULT_COUNTRY_CODE);
            if ( strlen(country_code) == 0 ) {
#ifdef DEBUG_GABY
                  /* the user should got this information but it could
                   * also have 'no area code' set and others and he
                   * doesn't want eight warning dialog boxes. I may put
                   * all the message in a buffer and show a warning box
                   * at the end.
                   */
                  debug_print("Warning : no country code set\n");
                  gaby_errno = CUSTOM_WARNING;
                  gaby_message = g_strdup(_("You didn't specify your country code"));
                  gaby_perror_in_a_box();
#endif
            }
            if ( strncmp(res+strlen(i18n_code), country_code, 
                              strlen(country_code)) == 0 ) {
                  memmove(res + strlen(ld_code), 
                        res + strlen(i18n_code) + strlen(country_code),
                        strlen(res)-strlen(ld_code));
                  memcpy(res, ld_code, strlen(ld_code));
            } else {
                  g_free(country_code);
                  g_free(i18n_code);
                  g_free(ld_code);
#ifdef DEBUG_GABY
                  debug_print("The current number is %s\n", res);
#endif
                  return TRUE;
            }
      }
      
      g_free(i18n_code);

      if ( strncmp(res, ld_code, strlen(ld_code)) == 0) {
            area_code = get_config_str("actions", "net", "area_code", 
                                          DEFAULT_AREA_CODE );
            if ( strlen(area_code) == 0 ) {
#ifdef DEBUG_GABY
                  debug_print("Warning : no area code set\n");
#endif
                  gaby_errno = CUSTOM_WARNING;
                  gaby_message = g_strdup(_("You didn't specify your area code"));
                  gaby_perror_in_a_box();
            }

            if ( strncmp(res+strlen(ld_code), area_code, 
                              strlen(area_code)) == 0 ) {
                  memmove(res, 
                        res + strlen(ld_code) + strlen(area_code),
                        strlen(res));
            }
            g_free(area_code);
      }
      g_free(ld_code);

#ifdef DEBUG_GABY
      debug_print("The current number is %s\n", res);
#endif

      return TRUE;
}

static void phone_reply_cb(gint reply, void **ptr)
{
      gchar *str;
      gchar *number;
      int *dec;
      char cmd[1000];
      char *s;
      GString *st;
      
      dec = ptr[0];
      number = ptr[1];
      g_free(ptr);
#ifdef DEBUG_GABY
      debug_print("reply : %d\n", reply);
#endif
      if ( reply != 0 ) {
            g_free(number);
            (*dec)--;
            /* TODO (post-2.0) ask the user to correct the number */
            return;
      }
      
      str = get_config_str("actions", "net", "cmd_phone", DEFAULT_PHONE_CMD);
      
#ifdef DEBUG_GABY
      debug_print("str : %s\n", str);
#endif
      if ( strstr(str, "$p") == NULL ) {
            sprintf(cmd,_("The command to use for phone numbers (%s) does "
                        "not have \"$p\" in it,\n which is the way to "
                        "tell it what is the phone number you want."),
                        str);
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(cmd);
            g_free(number);
            g_free(str);
            (*dec)--;
            return;
      }
      
      s = strstr(str, "$p"); s[0] = 0; s[1] = 0;

      st = g_string_new("");
      st = g_string_append(st, number);
      st = g_string_prepend(st, str);
      st = g_string_append(st, str+strlen(str)+2);
      
      strcpy(cmd, st->str);
      g_string_free(st, 1);

      debug_print("Executing: %s\n", cmd);
      system(cmd);

      g_free(number);
      g_free(str);

      (*dec)--;
}

/**
 * phone
 * @param1: phone number
 *
 * Description:
 * Dial the given phone number (usually using chat(8))
 */
mstatic void net_phone (struct action_param param[1], int *dec)
{
      union data fields[1];
      gchar *number;
      char question[1000];
      GtkWidget *dlg;
      void **ptr;
      
      memcpy(&fields[0], &param[0].val, sizeof(union data));
      
      if ( fields[0].str->len == 0 ) {
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(_("Unable to guess phone number."));
            (*dec)--;
            return;
      }

#ifdef DEBUG_GABY
      debug_print("the phone number is %s\n", fields[0].str->str);
#endif

      number = g_malloc(100);
      create_phone_number(number, fields[0].str->str);

#ifdef DEBUG_GABY
      debug_print("and I translated it to %s\n", number);
#endif
      
      ptr = g_malloc(sizeof(void*)*2);
      ptr[0] = dec;
      ptr[1] = number;

#ifdef USE_GNOME
      sprintf(question, _("Is %s correct ?"), number );
      dlg = gnome_question_dialog(question,
                  (GnomeReplyCallback)phone_reply_cb, ptr);
#else
      phone_reply_cb(0, ptr);
#endif
}




static GtkWidget *configure_widget = NULL;
static void configure_save();

#ifdef FOLLOW_MIGUEL
GtkWidget* net_configure()
#else
GtkWidget* configure()
#endif
{
      /* this had been created with glade and then modified by hand */
      GtkWidget *vbox;
      GtkWidget *frame;
      GtkWidget *table_email,
              *table_phone;
      GtkWidget *label;
      GtkWidget *combo_cmd_email, *entry_cmd_email;
      GtkWidget *om_format, *om_format_menu, *menuitem;
      GtkWidget *entry_cmd_phone,
              *entry_country,
              *entry_area,
              *entry_ldc,
              *entry_ic;
      gchar *str;
      
      static gchar* plugin_name = gettext_noop("Net");
                              /* or sth like mail&phone ?*/
#if 0
      if ( configure_widget && configure_widget->window ) {
            entry_cmd_email = gtk_object_get_data( 
                        GTK_OBJECT(configure_widget), "cmd_email");
            str = get_config_str("actions", "net", "cmd_email", 
                        DEFAULT_EMAIL_CMD);
#ifdef DEBUG_GABY
            debug_print("[actions:net:cfg] resetting cmd_email to %s\n", str);
#endif
            gtk_entry_set_text(GTK_ENTRY(entry_cmd_email), str);
            g_free(str);
            
            return configure_widget;
      }
#endif
      
      vbox = gtk_vbox_new(FALSE, 0);
      gtk_signal_connect(GTK_OBJECT(vbox), "destroy_event", 
                  destroy_configure_event, &configure_widget);
      gtk_widget_show(vbox);

      frame = gtk_frame_new(_("E-Mail"));
      gtk_widget_show(frame);
      gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
      gtk_container_border_width(GTK_CONTAINER(frame), 5);

      table_email = gtk_table_new(2, 2, FALSE);
      gtk_widget_show(table_email);
      gtk_container_add(GTK_CONTAINER(frame), table_email);
      gtk_container_border_width(GTK_CONTAINER(table_email), 5);
      gtk_table_set_row_spacings(GTK_TABLE(table_email), 7);
      gtk_table_set_col_spacings(GTK_TABLE(table_email), 5);

      label = gtk_label_new(_("Command to execute :"));
      gtk_widget_show(label);
      gtk_table_attach(GTK_TABLE(table_email), label, 0, 1, 0, 1,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      combo_cmd_email = gtk_combo_new();
      {
            char *cmd[] = {
                  "mozilla -mail mailto:\"$e\"",
                  "xterm -e mutt \"$e\"",
                  NULL
            };
            int i=0;
            GList *strings = NULL;
            while ( cmd[i] ) {
                  strings = g_list_append(strings, cmd[i]);
                  i++;
            }
            gtk_combo_set_popdown_strings(GTK_COMBO(combo_cmd_email),
                                                strings);
            g_list_free(strings);
      }
            
      entry_cmd_email = GTK_COMBO(combo_cmd_email)->entry;
      str = get_config_str("actions", "net", "cmd_email", DEFAULT_EMAIL_CMD);
      gtk_object_set_data(GTK_OBJECT(vbox), "cmd_email", entry_cmd_email);
      gtk_entry_set_text(GTK_ENTRY(entry_cmd_email), str);
      g_free(str);
      gtk_signal_connect(GTK_OBJECT(entry_cmd_email), "changed", 
                  GTK_SIGNAL_FUNC(gaby_property_box_changed), vbox);
      gtk_widget_show(combo_cmd_email);
      gtk_table_attach(GTK_TABLE(table_email), combo_cmd_email, 1, 2, 0, 1,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      label = gtk_label_new(_("Address format :"));
      gtk_widget_show(label);
      gtk_table_attach(GTK_TABLE(table_email), label, 0, 1, 1, 2,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      om_format = gtk_option_menu_new();
      gtk_widget_set_sensitive(om_format, FALSE);
      gtk_widget_show(om_format);
      gtk_table_attach(GTK_TABLE(table_email), om_format, 1, 2, 1, 2,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);
      om_format_menu = gtk_menu_new();
      menuitem = gtk_menu_item_new_with_label("Joe Linux User <joe@linux.org>");
      gtk_widget_show(menuitem);
      gtk_menu_append(GTK_MENU(om_format_menu), menuitem);
      menuitem = gtk_menu_item_new_with_label("joe@linux.org");
      gtk_widget_show(menuitem);
      gtk_menu_append(GTK_MENU(om_format_menu), menuitem);
      menuitem = gtk_menu_item_new_with_label("joe@linux.org (Joe Linux User)");
      gtk_widget_show(menuitem);
      gtk_menu_append(GTK_MENU(om_format_menu), menuitem);
      gtk_option_menu_set_menu(GTK_OPTION_MENU(om_format), om_format_menu);

      frame = gtk_frame_new(_("Phone"));
      gtk_widget_show(frame);
      gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
      gtk_container_border_width(GTK_CONTAINER(frame), 5);

      table_phone = gtk_table_new(5, 2, FALSE);
      gtk_widget_show(table_phone);
      gtk_container_add(GTK_CONTAINER(frame), table_phone);
      gtk_container_border_width(GTK_CONTAINER(table_phone), 5);
      gtk_table_set_row_spacings(GTK_TABLE(table_phone), 5);
      gtk_table_set_col_spacings(GTK_TABLE(table_phone), 5);

      label = gtk_label_new(_("Command to execute :"));
      gtk_widget_show(label);
      gtk_table_attach(GTK_TABLE(table_phone), label, 0, 1, 0, 1,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      entry_cmd_phone = gtk_entry_new();
      str = get_config_str("actions", "net", "cmd_phone", DEFAULT_PHONE_CMD);
      gtk_object_set_data(GTK_OBJECT(vbox), "cmd_phone", entry_cmd_phone);
      gtk_entry_set_text(GTK_ENTRY(entry_cmd_phone), str);
      g_free(str);
      gtk_widget_show(entry_cmd_phone);
      gtk_table_attach(GTK_TABLE(table_phone), entry_cmd_phone, 1, 2, 0, 1,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);
      
      label = gtk_label_new(_("Country code :"));
      gtk_widget_show(label);
      gtk_table_attach(GTK_TABLE(table_phone), label, 0, 1, 1, 2,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      entry_country = gtk_entry_new();
      str = get_config_str("actions", "net", "country_code", 
                                    DEFAULT_COUNTRY_CODE);
      gtk_object_set_data(GTK_OBJECT(vbox), "country_code", entry_country);
      gtk_entry_set_text(GTK_ENTRY(entry_country), str);
      g_free(str);
      gtk_widget_show(entry_country);
      gtk_table_attach(GTK_TABLE(table_phone), entry_country, 1, 2, 1, 2,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      label = gtk_label_new(_("Area code :"));
      gtk_widget_show(label);
      gtk_table_attach(GTK_TABLE(table_phone), label, 0, 1, 2, 3,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      entry_area = gtk_entry_new();
      str = get_config_str("actions", "net", "area_code", 
                                    DEFAULT_AREA_CODE);
      gtk_object_set_data(GTK_OBJECT(vbox), "area_code", entry_area);
      gtk_entry_set_text(GTK_ENTRY(entry_area), str);
      g_free(str);
      gtk_widget_show(entry_area);
      gtk_table_attach(GTK_TABLE(table_phone), entry_area, 1, 2, 2, 3,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      label = gtk_label_new(_("Prefix for long distance calls :"));
      gtk_widget_show(label);
      gtk_table_attach(GTK_TABLE(table_phone), label, 0, 1, 3, 4,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      entry_ldc = gtk_entry_new();
      str = get_config_str("actions", "net", "long_distance_code", 
                                    DEFAULT_LONG_DISTANCE_CODE);
      gtk_object_set_data(GTK_OBJECT(vbox), "long_distance_code", entry_ldc);
      gtk_entry_set_text(GTK_ENTRY(entry_ldc), str);
      g_free(str);
      gtk_widget_show(entry_ldc);
      gtk_table_attach(GTK_TABLE(table_phone), entry_ldc, 1, 2, 3, 4,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      label = gtk_label_new(_("Prefix for international calls :"));
      gtk_widget_show(label);
      gtk_table_attach(GTK_TABLE(table_phone), label, 0, 1, 4, 5,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);

      entry_ic = gtk_entry_new();
      str = get_config_str("actions", "net", "international_code", 
                                    DEFAULT_INTERNATIONAL_CODE);
      gtk_object_set_data(GTK_OBJECT(vbox), "international_code", entry_ic);
      gtk_entry_set_text(GTK_ENTRY(entry_ic), str);
      g_free(str);
      gtk_widget_show(entry_ic);
      gtk_table_attach(GTK_TABLE(table_phone), entry_ic, 1, 2, 4, 5,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL,
                   (GtkAttachOptions) GTK_EXPAND | GTK_FILL, 0, 0);
      
      gtk_object_set_data(GTK_OBJECT(vbox), "name", plugin_name);
      gtk_object_set_data(GTK_OBJECT(vbox), "cfg_save", configure_save);

      configure_widget = vbox;
      
      return vbox;
}

static void configure_save()
{
      GtkEntry *entry;
      gchar *st;
      
      entry = gtk_object_get_data(GTK_OBJECT(configure_widget), "cmd_email");
      st = gtk_entry_get_text(entry);
      write_config_str("actions", "net", "cmd_email", st);
      
      entry = gtk_object_get_data(GTK_OBJECT(configure_widget), "cmd_phone");
      st = gtk_entry_get_text(entry);
      write_config_str("actions", "net", "cmd_phone", st );
      
      entry = gtk_object_get_data(GTK_OBJECT(configure_widget), 
                                          "country_code");
      st = gtk_entry_get_text(entry);
      write_config_str("actions", "net", "country_code", st );
      
      entry = gtk_object_get_data(GTK_OBJECT(configure_widget), "area_code");
      st = gtk_entry_get_text(entry);
      write_config_str("actions", "net", "area_code", st );
      
      entry = gtk_object_get_data(GTK_OBJECT(configure_widget), 
                                          "long_distance_code");
      st = gtk_entry_get_text(entry);
      write_config_str("actions", "net", "long_distance_code", st );
      
      entry = gtk_object_get_data(GTK_OBJECT(configure_widget), 
                                          "international_code");
      st = gtk_entry_get_text(entry);
      write_config_str("actions", "net", "international_code", st );
      
}


/*
 * dtmf-dial 0.1
 * (C) 1998 Itai Nahshon (nahshon@actcom.co.il)
 *
 * Use and redistribution are subject to the GNU GENERAL PUBLIC LICENSE.
 *
 * Modified by Frederic Peters (fpeters@tiscalinet.be) to work as a gaby
 * action.
 */


#ifdef HAVE_LINUX_SOUNDCARD_H
#include <math.h>
#include <linux/soundcard.h>
#include <sys/ioctl.h>

static short* gen_costab(void);
static void dial_digit(int c, int *speed, signed short *costab,
                   unsigned char *buf, int *bufidx, int fd, int *dialed);
static void silent(int msec, int *bufidx, unsigned char *buf, int *dialed,
               int fd);
static void dial(int f1, int f2, int msec, int *speed, signed short *costab,
             unsigned char *buf, int *bufidx, int fd, int *dialed);

#define DTMF_OUTPUT           "/dev/dsp"
#define DTMF_FORMAT           AFMT_U8
#define DTMF_BITS       8
#define DTMF_SPEED            8000
#define DTMF_TONE_TIME        100
#define DTMF_SILENT_TIME      50
#define DTMF_SLEEP_TIME       500
#define DTMF_VOLUME           100
#define DTMF_BUFSIZE          4096
#define DTMF_TABSIZE          256

static int initialize_audiodev(int fd)
{
      int speed_local = DTMF_SPEED;
      int speed = DTMF_SPEED;
      int channels = 1;
      int format = DTMF_FORMAT;
      int diff;

      if(ioctl(fd, SNDCTL_DSP_CHANNELS, &channels)) {
#ifdef DEBUG_GABY
            perror("ioctl(SNDCTL_DSP_CHANNELS)");
#endif
            return 0;
      }

      if(ioctl(fd, SNDCTL_DSP_SETFMT, &format)) {
#ifdef DEBUG_GABY
            perror("ioctl(SNDCTL_DSP_SPEED)");
#endif
            return 0;
      }

      if(ioctl(fd, SNDCTL_DSP_SPEED, &speed_local)) {
#ifdef DEBUG_GABY
            perror("ioctl(SNDCTL_DSP_SPEED)");
#endif
            return 0;
      }

      diff = speed_local - speed;
      if(diff < 0)
            diff = -diff;
      if(diff > 500) {
#ifdef DEBUG_GABY
            debug_print("Your sound card does not support the requested speed\n");
#endif
            return 0;
      }
      
      if(diff != 0) {
#ifdef DEBUG_GABY
            debug_print("Setting speed to %d\n", speed_local);
#endif
      }
      speed = speed_local;

      return speed;
}

mstatic void net_dtmfdial(struct action_param param[1], int *dec)
{
      char *cp, number[50];
      int fd;
      int speed;
      signed short *costab;
      int bufidx;
      unsigned char *buf;
      int dialed = 0;
      union data fields[1];
      
      memcpy(&fields[0], &param[0].val, sizeof(union data));
      
      if ( fields[0].str->len == 0 ) {
            gaby_errno = CUSTOM_ERROR;
            gaby_message = g_strdup(_("Unable to guess phone number."));
            (*dec)--;
            return;
      }


      fd = open(DTMF_OUTPUT, O_CREAT|O_TRUNC|O_WRONLY, 0644);
      if (fd < 0) {
#ifdef DEBUG_GABY
            debug_print("Unable to open %s", DTMF_OUTPUT);
#endif
            (*dec)--;
            return;
      }

      speed = initialize_audiodev(fd);
      if ( speed == 0 ) {
            close(fd);
            (*dec)--;
            return;
      }

      costab = gen_costab();
      if ( costab == NULL ) {
            close(fd);
            (*dec)--;
            return;
      }

      buf = g_malloc(DTMF_BUFSIZE);
      if(buf == NULL) {
            close(fd);
            (*dec)--;
            return;
      }

      create_phone_number(number, fields[0].str->str);

      bufidx = 0;
      cp = number;
      if (dialed)
            silent(DTMF_SLEEP_TIME, &bufidx, buf, &dialed, fd);
      while (cp && *cp) {
            if (*cp == ',' || *cp == ' ')
                  silent(DTMF_SLEEP_TIME, &bufidx, buf, &dialed,fd);
            else {
                  if(dialed)
                        silent(DTMF_SILENT_TIME, &bufidx, buf,
                                    &dialed, fd);
                  dial_digit(*cp, &speed, costab, buf, &bufidx,
                              fd, &dialed);
            }
            cp++;
      }
      
      if(bufidx > 0) {
            write(fd, buf, bufidx);
      }

      close(fd);
      (*dec)--;
}

static void dial_digit(int c, int *speed, signed short *costab,
                   unsigned char *buf, int *bufidx, int fd, int *dialed) {
      switch(c) {
            case '0':
                  dial(941, 1336, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '1':
                  dial(697, 1209, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
            break;
            case '2':
                  dial(697, 1336, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '3':
                  dial(697, 1477, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
            break;
            case '4':
                  dial(770, 1209, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '5':
                  dial(770, 1336, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '6':
                  dial(770, 1477, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '7':
                  dial(852, 1209, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '8':
                  dial(852, 1336, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '9':
                  dial(852, 1477, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case '*':
                  dial(941, 1209, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
            break;
            case '#':
                  dial(941, 1477, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case 'A':
                  dial(697, 1633, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case 'B':
                  dial(770, 1633, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case 'C':
                  dial(852, 1633, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
            case 'D':
                  dial(941, 1633, DTMF_TONE_TIME, speed, 
                              costab, buf, bufidx, fd, dialed);
                  break;
      }
}

static void silent(int msec, int *bufidx, unsigned char *buf, int *dialed,
               int fd) {
      int time;
      if(msec <= 0)
            return; 

      time = (msec * DTMF_SPEED) / 1000;
      while(--time >= 0) {
            buf[*(bufidx++)] = 128;
            if(*bufidx >= DTMF_BUFSIZE) {
                  write(fd, buf, DTMF_BUFSIZE);
                  *bufidx = 0;
            }
      }
      dialed = 0;
}

static void dial(int f1, int f2, int msec, int *speed, signed short *costab,
             unsigned char *buf, int *bufidx, int fd, int *dialed) {
      int i1, i2, d1, d2, e1, e2, g1, g2;
      int time;
      int val;

      if(msec <= 0)
            return;

      f1 *= DTMF_TABSIZE;
      f2 *= DTMF_TABSIZE;
      d1 = f1 / *speed;
      d2 = f2 / *speed;
      g1 = f1 - d1 * *speed;
      g2 = f2 - d2 * *speed;
      e1 = *speed/2;
      e2 = *speed/2;

      i1 = i2 = 0;

      time = (msec * *speed) / 1000;
      while(--time >= 0) {
            val = costab[i1] + costab[i2];

            buf[*(bufidx++)] = 128 + (val >> 8); 

            i1 += d1;
            if (e1 < 0) {
                  e1 += *speed;
                  i1 += 1;
            }
            if (i1 >= DTMF_TABSIZE)
                  i1 -= DTMF_TABSIZE;

            i2 += d2;
            if (e2 < 0) {
                  e2 += *speed;
                  i2 += 1;
            }
            if (i2 >= DTMF_TABSIZE)
                  i2 -= DTMF_TABSIZE;

            if(*bufidx >= DTMF_BUFSIZE) {
                  write(fd, buf, DTMF_BUFSIZE);
                  *bufidx = 0;
            }
            e1 -= g1;
            e2 -= g2;
      }
      *dialed = 1;
}

static short* gen_costab(void) {
      int i;
      double d;
      short *costab;

      costab = (signed short *)g_malloc(DTMF_TABSIZE * sizeof(signed short));
      if(costab == NULL) {
            return NULL;
      }

      for (i = 0; i < DTMF_TABSIZE; i++) {
            d = 2*M_PI*i;
            costab[i] = (int)((DTMF_VOLUME/100.0)*16383.0*cos(d/DTMF_TABSIZE));
      }
      return costab;
}

#endif /* HAVE_LINUX_SOUNDCARD_H */


Generated by  Doxygen 1.6.0   Back to index