/*
 **********************************************************************
 * Xztalk 1.1 by Liem Bahneman (roland@cac.washington.edu)
 * and Andy Burnett (burnett@baldrick.cecer.army.mil) 
 * This is the graphical interface to the ztalk application by Scott Doty
 * (scott@cs.santarosa.edu). 
 * 
 * I'm including this tidbit FYI: 
 **********************************************************************
 */

/* Copyright (C) 1993 Free Software Association of Germany

   The following is only valid, if you use this outside the Federal
   Republic of Germany.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GU General Public License as published by
   the Free Software Foundation; either version 2, 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 impliedwarranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   If you don't have a a copy of the GNU General Public License
   write to the Free Software Foundation, Inc., 675 Mass Ave, 
  Cambridge, MA 02139, USA.

   (C)opyright 1993,1994 FREE SOFTWARE ASSOCIATION OF GERMANY
*/

#include <stdio.h>
#include <varargs.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <dirent.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <sys/soundcard.h>
#include <linux/time.h>
#include <time.h>
#include "ztalk.h"
#include "gsm.h"
#include "ul2s.h"


#include <X11/Xlib.h>
#include <X11/Intrinsic.h>

#ifdef XPM
#include "xpm.h"
#endif

#include <Xm/List.h>
#include <Xm/LabelG.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/MessageB.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/FileSB.h>
#include <Xm/ToggleB.h>
#include <Xm/ScrollBar.h>
#include <Xm/Separator.h>

#ifdef TERM
#include "client.h"
#endif

/* The soundcard junk */
Widget mic, vol, line;
Widget lb;

short scOpen = 0;
short amOpen = 0;
int piped = 0;
int pp[2];
FILE *tfp;
int tp;

#define MIC 7
#define VOL 0
#define LINE 6

#ifndef XPM
#include "xztalk.icon"
#endif

int hostCnt = 0;

#define MAX_NICKS 100

char MailMessages[BUFSIZ];
char Recipients[BUFSIZ];

typedef struct _hostNick {
  char *nick;
  char *host;
} NickNames;

#define AUDIO "/dev/audio"
#define TCP_PORT_ZTALK 5109

/* this is the path to your .au files */
/*#define AU_PATH "*.au"*/

NickNames Nicks[MAX_NICKS];

/*
 ****************************************
 * this is stuff right from ztalk.c 
 ****************************************
 */

int VERBOSE = 1;

static unsigned char buf_record[SIZE_MB]; /* sd: that outta clear the rug. */

int pos_record = 0;

#ifndef INADD_NONE
#define INADD_NONE 
#endif

struct sockaddr_in      tcp_srv_addr;
struct sockaddr_in      myctladdr;
struct sockaddr_in      data_addr;
struct servent          tcp_serv_info;
struct hostent          tcp_host_info;

int     samps_read=0;           /* samples read from (/dev) AUDIO */
int     audio=-1;               /* handle to audio device */
int     stat_compressor = 0;    /* status from compressor call */
int     stat_transmit = 0;      /* status from transmit call */
int     size_send = 0;          /* send buffer size */

char current_ip[100];
char host[100];
int great_errno; 

#ifndef lint

static  char copyright[] =
"Copyright (c) 1994 Scott Doty, released under conditions of the GPL.\n"
"Portions Copyright (c) 1993, 1994 Free Software Association of Germany.\n";
#endif

#ifndef lint
static char sccsid[] = "@(#) ztalk  Version 0.2a"
                       " Mon Mar 28 03:34:28 PST 1994\n";
#endif 
    
#ifndef FD_SETSIZE
/* Forward compatability */
#define FD_SET(n, p)    ((p)->fds_bits[0] |= (1<<(n)))
#define FD_CLR(n, p)    ((p)->fds_bits[0] &= ~(1<<(n)))
#define FD_ISSET(n, p)  ((p)->fdsbits[0] & (1<<(n)))
#define FD_ZERO(p)      ((p)->fds_bits[0] = 0)
#endif

/*
 ***************************************
 * done ztalk stuff...begin Xztalk stuff
 ***************************************
 */

extern char *strcpy();

/* status of recording..yea or nay */
int recording = 0;
/* status of sending file or not */
int send_a_file = 0;

Widget list_w, viewport, to_who, transmit;
Widget CreateLabeledTextForm(), term_port;
Widget t1, t2, audio_entry, toggle_aufile;

/* function prototypes */

void add_user(), add_to_to(), wprint(), addHost(), addOkCB(), addCancelCB();
void au_file(), toggled(), deleteUser(), deleteHostEntry();
void send_file(), toggled2(), sliderCB(), scDismiss(), scOptions(), vmPlayCB();
void playMailMessage(), mailMessageSet(), setRecipients();
char *fixstr();

int addHostEntry(), findEntry(), do_transmit();
void save_rc();

/* this is what does the sampling */
XtWorkProc record_proc();

METHOD method = ME_GSM;

/* for .ztalkrc */
FILE *fp;
FILE *foo;

Widget toplevel;

/* These only take effect if the app-defaults file is not found */
String fallback_resources[] = {
    "*XmText.fontList: -*-courier-medium-r-*--12-*",
    "*XmText.translations: #override \
        Ctrl<Key>D: activate() \n\
        Ctrl<Key>U: kill-to-start-of-line() \n\
        Ctrl<Key>W: delete-previous-word() \n\
        <Key>osfDelete: delete-previous-character()",
    "*msg-text.rows: 15",
    "*msg-text.columns: 35",
    "*XmPushButton.fontList: -*-new century schoolbook-bold-r-*--12-*",
    "*XmPushButtonGadget.fontList: -*-new century schoolbook-bold-r-*--12-*",
    "*XmLabelGadget.fontList: -*-new century schoolbook-bold-r-*--12-*",
    "*XmList.fontList: -*-courier-medium-r-*--12-*",
    "*XmToggleButton.fontList: -*-new century schoolbook-bold-r-*--12-*",
    "*XmLabel.fontList: -*-new century schoolbook-bold-r-*--12-*",
    "*xztalk.labelString: Xztalk",
    "*title.labelString: Quick Talk Sender",
    "*actions*leftAttachment: attach_position",
    "*actions*rightAttachment: attach_position",
    "*audio_w*leftAttachment: attach_position",
    "*audio_w*rightAttachment: attach_position",
    "*au-label.labelString: Audio File:",
    "*to-list.visibleItemCount: 6",
    "*add-btn.labelString: Add ...",
    "*delete-btn.labelString: Delete",
    "*save-btn.labelString: Save",
    "*quit-btn.labelString: Quit",
    "*audio-file.labelString: Select audio file",
    "*scValues.labelString: Soundcard Settings",
    "*scDialog.title: Sound Card Settings",
    "*vmail.labelString: Answering Machine",
    NULL
};

main(argc, argv)
int argc;
char *argv[];
{
  Widget left_side, logo_stuff, icon, titles, actions, main_frame , w, rc2;
  Widget toggle_vmail, rc3, sep1, sep2, two_entries, to_label;
  Widget port_label, entry_form;
  extern Widget audio_entry;

  XtAppContext app;
  char initfile[100];

  XtWorkProcId record;
  Arg args[10];
  int n;
  Pixel fg, bg;

#ifdef XPM
  Pixmap addicon,delicon,logoicon,saveicon,exiticon;
  extern Pixmap ReadXPM();
  char XPMPATH2[100];
#else
  Pixmap pixmap;
#endif

  extern void exit();
  XmString trans_label, new_entry;
  
  char nickname[40];
  
  XtSetLanguageProc (NULL, NULL, NULL);

  /* open up .ztalkrc addressbook */
  sprintf(initfile, "%s/.ztalkrc", getenv("HOME"));
  if ((fp=fopen(initfile, "r+"))==NULL) { 
/*    exit();*/
  }
  
/*
 ****************************************
 * widgets and widgets and widgets 
 ****************************************
 */
  
  signal(SIGCHLD, SIG_IGN);
  
  toplevel = XtVaAppInitialize (&app, "Xztalk", NULL, 0,
				&argc, argv, fallback_resources,
				XmNallowShellResize,  True,
				NULL);
  
  main_frame = XtVaCreateWidget ("main_frame", 
				 xmRowColumnWidgetClass, toplevel,
				 XmNorientation, XmHORIZONTAL,
				 NULL);
  
  left_side = XtVaCreateWidget ("left_side", xmRowColumnWidgetClass, 
				main_frame, NULL);
  
  logo_stuff = XtVaCreateWidget ("logo_stuff", xmFormWidgetClass, 
				 left_side, NULL);
  /* read in icon */  
  XtVaGetValues (logo_stuff, 
		 XmNforeground, &fg, 
		 XmNbackground, &bg, 
		 NULL);
#ifndef XPM
  pixmap = XCreatePixmapFromBitmapData (XtDisplay (logo_stuff),
				RootWindowOfScreen(XtScreen(logo_stuff)),
				xztalk_logo_bits, xztalk_logo_width,
				xztalk_logo_height,
				fg, bg,
				DefaultDepthOfScreen(XtScreen(logo_stuff)));
#else
  /* load xpm icons */
  sprintf(XPMPATH2, "%s/%s", XPMPATH, "xztalk.xpm");
  logoicon = ReadXPM(XPMPATH2);
  sprintf(XPMPATH2, "%s/%s", XPMPATH, "save.xpm"); 
  saveicon = ReadXPM(XPMPATH2);
  sprintf(XPMPATH2, "%s/%s", XPMPATH, "del.xpm");
  delicon = ReadXPM(XPMPATH2);
  sprintf(XPMPATH2, "%s/%s", XPMPATH, "add.xpm");
  addicon = ReadXPM(XPMPATH2);
  sprintf(XPMPATH2, "%s/%s", XPMPATH, "exit.xpm");
  exiticon = ReadXPM(XPMPATH2);
#endif

  icon = XtVaCreateManagedWidget ("xztalk_icon", 
				  xmLabelGadgetClass, logo_stuff,
				  XmNleftAttachment,  XmATTACH_FORM,
#ifdef XPM
				  XmNlabelType,       XmPIXMAP,
				  XmNlabelPixmap,     logoicon,
#else
                                  XmNlabelType,       XmPIXMAP,
                                  XmNlabelPixmap,     pixmap,
#endif
				  XmNalignment,       XmALIGNMENT_END,
				  NULL);
  
  /* identify the program */

  titles = XtVaCreateWidget ("titles",
			     xmRowColumnWidgetClass, logo_stuff,
			     XmNrightAttachment,  XmATTACH_FORM,
			     XmNleftAttachment,   XmATTACH_WIDGET,
			     XmNleftWidget,       icon,
			     XmNtopAttachment,    XmATTACH_FORM,
			     XmNbottomAttachment, XmATTACH_FORM,
			     NULL);
  XtVaCreateManagedWidget ("xztalk", xmLabelGadgetClass, titles, NULL);
  XtVaCreateManagedWidget ("title", xmLabelGadgetClass, titles, NULL);
  XtManageChild (titles);
  XtManageChild (logo_stuff);
  
  /* provide the "To:" prompt (see the resources above) */


  entry_form = XtVaCreateManagedWidget("entry_form", xmFormWidgetClass,
				       left_side, XmNorientation, XmHORIZONTAL,
				       XmNfractionBase, 10, XmNwidth, 200,
				       XmNleftAttachment, XmATTACH_FORM,
				       XmNrightAttachment, XmATTACH_FORM,
				       NULL);

  to_label = XtVaCreateManagedWidget ("to-label", 
				      xmLabelGadgetClass, entry_form,
				      XmNlabelString, 
				      XmStringCreateSimple("To:"),
				      XmNleftAttachment, XmATTACH_POSITION,
				      XmNleftPosition, 0,
				      XmNtopAttachment,    XmATTACH_FORM,
				      XmNbottomAttachment, XmATTACH_FORM,
				      XmNrightAttachment, XmATTACH_POSITION,
				      XmNrightPosition, 1,
				      NULL);

  to_who = XtVaCreateManagedWidget ("to", 
				    xmTextWidgetClass, entry_form,
				    XmNtopAttachment,    XmATTACH_FORM,
				    XmNbottomAttachment, XmATTACH_FORM,
				    XmNleftAttachment, XmATTACH_POSITION,
				    XmNleftPosition, 1,
				    XmNrightAttachment, XmATTACH_POSITION,
				    XmNrightPosition, 6,
				    NULL);

  port_label = XtVaCreateManagedWidget ("port-label",
					xmLabelGadgetClass, entry_form,
					XmNlabelString, 
					XmStringCreateSimple("Port:"),
					XmNtopAttachment,    XmATTACH_FORM,
					XmNbottomAttachment, XmATTACH_FORM,
					XmNleftAttachment, XmATTACH_POSITION,
					XmNleftPosition, 6,
					XmNrightAttachment, XmATTACH_POSITION,
					XmNrightPosition, 8,
					NULL);

  term_port = XtVaCreateManagedWidget ("term_port",
				       xmTextWidgetClass, entry_form,
				       XmNleftAttachment, XmATTACH_POSITION,
				       XmNleftPosition, 8,
				       XmNtopAttachment,    XmATTACH_FORM,
				       XmNrightAttachment, XmATTACH_POSITION,
				       XmNrightPosition, 10,
				       XmNbottomAttachment, XmATTACH_FORM,
				       NULL);

  XtVaSetValues(term_port,XmNvalue, "5109", NULL);

  /* the transmit record button */
  
  trans_label = XmStringCreateSimple("Press to Record");
  transmit = XtVaCreateManagedWidget("Transmit",
				     xmPushButtonWidgetClass,
				     left_side, XmNlabelString,
				     trans_label,
				     NULL);
  XmStringFree(trans_label);
  
  /* when user hits <Return>, advance caret to next input item */
  XtAddCallback (transmit, XmNactivateCallback, (void *) do_transmit, NULL);
  
  /* right side is a scrolled text region for letter input. */
  n = 0;
  XtSetArg (args[n], XmNeditMode,          XmMULTI_LINE_EDIT); n++;
  XtSetArg (args[n], XmNscrollVertical,    True); n++;
  XtSetArg (args[n], XmNscrollHorizontal,  True); n++;
  XtSetArg (args[n], XmNeditable, False); n++;
  XtSetArg (args[n], XmNcursorPositionVisible, False); n++;
  XtSetArg (args[n], XmNrows, 18); n++;
  XtSetArg (args[n], XmNcolumns, 55); n++;
  
  viewport = XmCreateScrolledText (main_frame, "msg-text", args, n);
  XtManageChild (viewport);
  
  /* Create a ScrolledList of all the recipients entered in To: */
  n = 0;
  XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
  XtSetArg (args[n], XmNselectionPolicy, XmEXTENDED_SELECT); n++;
  XtSetArg (args[n], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE); n++;

  list_w = XmCreateScrolledList (left_side, "to-list", args, n);
  XtAddCallback (list_w, XmNdefaultActionCallback, setRecipients, to_who);
  XtAddCallback(list_w, XmNextendedSelectionCallback, setRecipients, NULL);
  XtManageChild (list_w);
  
  /* Any command line args are recipients */
  while (argc-- > 1) {
    XmString str = XmStringCreateLocalized (*++argv);
    XmListAddItemUnselected (list_w, str, 0);
    XmStringFree (str);
  }
  
  /* Add, Delete, Save and Quit buttons */
  actions = XtVaCreateWidget ("actions", xmFormWidgetClass, left_side, 
			      NULL);

  w = XtVaCreateManagedWidget ("add-btn",
			       xmPushButtonWidgetClass, actions,
			       XmNleftAttachment, XmATTACH_POSITION,
			       XmNleftPosition, 0,
			       XmNrightAttachment, XmATTACH_POSITION,
			       XmNrightPosition, 23,
#ifdef XPM
			       XmNlabelType, XmPIXMAP,
			       XmNlabelPixmap, addicon,
#endif
			       NULL);
  
  /* clicking on Add user adds user to scrolled list */
  XtAddCallback (w, XmNactivateCallback, addHost, (XtPointer) 1);
  
  /* Make it appear as tho hitting return in To: text widget
   * is just like clicking on the Add button.
   */
/*  XtAddCallback (to_who, XmNactivateCallback, add_user, w);*/
  
  w = XtVaCreateManagedWidget ("delete-btn",
			       xmPushButtonWidgetClass, actions,
			       XmNleftAttachment, XmATTACH_POSITION,
			       XmNleftPosition, 26,
			       XmNrightAttachment, XmATTACH_POSITION,
			       XmNrightPosition, 49,
#ifdef XPM
			       XmNlabelType, XmPIXMAP,
                               XmNlabelPixmap, delicon,
#endif
			       NULL);
  
  /* clicking on delete calls add_user() with a 0 client_data */
  XtAddCallback (w, XmNactivateCallback, deleteUser, (XtPointer) 0);
  
  w = XtVaCreateManagedWidget ("quit-btn",
			       xmPushButtonWidgetClass, actions,
			       XmNleftAttachment, XmATTACH_POSITION,
			       XmNleftPosition, 78,
			       XmNrightAttachment, XmATTACH_POSITION,
			       XmNrightPosition, 100,
#ifdef XPM
			       XmNlabelType, XmPIXMAP,
                               XmNlabelPixmap, exiticon,
#endif
			       NULL);
  XtAddCallback (w, XmNactivateCallback, exit, NULL);
  
  w = XtVaCreateManagedWidget ("save-btn",
			       xmPushButtonWidgetClass, actions,
			       XmNleftAttachment, XmATTACH_POSITION,
			       XmNleftPosition, 52,
			       XmNrightAttachment, XmATTACH_POSITION,
			       XmNrightPosition, 75,
#ifdef XPM
			       XmNlabelType, XmPIXMAP,
                               XmNlabelPixmap, saveicon,
#endif
			       NULL);
  XtAddCallback (w, XmNactivateCallback, save_rc, NULL);

  sep1 = XtVaCreateManagedWidget("sep1", xmSeparatorWidgetClass, left_side,
				 NULL);

  rc3 = XtVaCreateManagedWidget("rc3", xmRowColumnWidgetClass, left_side,
                                XmNorientation, XmHORIZONTAL, NULL);

  w = XtVaCreateManagedWidget("vmail", xmPushButtonWidgetClass, rc3,
			      XmNwidth, 80,
			      NULL);

  XtAddCallback(w, XmNactivateCallback, vmPlayCB, NULL);

  w = XtVaCreateManagedWidget("scValues", xmPushButtonWidgetClass,
			      rc3,
			      XmNwidth, 80,
			      NULL);
  XtAddCallback(w, XmNactivateCallback, scOptions, NULL);

  sep2 = XtVaCreateManagedWidget("sep2", xmSeparatorWidgetClass, left_side,
                                 NULL);
    
  /* stuff for selecting an audiofile for transmission */

  w = XtVaCreateManagedWidget ("audio-file", xmPushButtonWidgetClass, 
			       left_side,
			       XmNwidth, 80,
			       NULL);
  
  XtAddCallback (w, XmNactivateCallback, au_file, NULL);
  
/*  audio_entry = XtVaCreateManagedWidget("audio_entry", 
					xmTextWidgetClass, left_side, 
					NULL);*/

  audio_entry = CreateLabeledTextForm (left_side, "au-label", "au");

  /* toggle for sending a file or not */

  rc2 = XtVaCreateManagedWidget("rc2", xmRowColumnWidgetClass, left_side,
				XmNorientation, XmHORIZONTAL, NULL);

  toggle_aufile = XtVaCreateManagedWidget("toggle_aufile", 
					  xmToggleButtonWidgetClass, rc2,
					  XmNlabelString,
					  XmStringCreateSimple("Send audio file"),
					  NULL);
  XtAddCallback(toggle_aufile, XmNvalueChangedCallback, toggled, NULL);
 
 toggle_vmail = XtVaCreateManagedWidget("toggle_vmail",
                                          xmToggleButtonWidgetClass, rc2,
                                          XmNlabelString,
                                          XmStringCreateSimple("VMail logging"),
                                          NULL);
  XtAddCallback(toggle_vmail, XmNvalueChangedCallback, toggled2, NULL);

  XtManageChild (actions);
  XtManageChild (left_side);
  XtManageChild (main_frame);
  
  /* specify tab groups in the order we'd like tabbing to follow */
  XtVaSetValues (to_who, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL);
  XtVaSetValues (transmit, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL);
  XtVaSetValues (viewport, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL);
  XtVaSetValues (actions, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL);
  XtVaSetValues (list_w, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL);
  
  record = XtAppAddWorkProc(app, (XtWorkProc)record_proc, NULL);

  /* open up the .ztalkrc file and put the entries in the list box for use */
  
  wprint("opening .ztalkrc: \n");
  while (!feof(fp)) {
    if ((fscanf(fp, "%s %s", nickname, host)) == 2){
      wprint("user: %s at host %s added.\n", nickname, host); 
      new_entry = XmStringCreateSimple(nickname);
      Nicks[hostCnt].nick = (char *) malloc(strlen(nickname) + 1); 
      strcpy(Nicks[hostCnt].nick, nickname);
      Nicks[hostCnt].host = (char *) malloc(strlen(host) + 1);
      strcpy(Nicks[hostCnt].host, host);
      XmListAddItem(list_w, new_entry, 0);
      XmStringFree(new_entry);
      ++hostCnt;
    }
  }
  fclose(fp);

  /* check to see if /tmp/.ztalk_away exists and toggle toggle_vmail */

  if ((foo=fopen("/tmp/.ztalk_away", "r"))==NULL) {    
    XtVaSetValues(toggle_vmail, XmNset, 0, NULL);
    wprint("Voice Mail logging not enabled.\n");
  } else {
    XtVaSetValues(toggle_vmail, XmNset, 1, NULL);
    wprint("Voice Mail logging in progress.\n");
  }
  close(foo);

  wprint("done.\n");
  wprint("Ready.\n");
  XtRealizeWidget (toplevel);
  XtAppMainLoop (app);
}

/* 
 ************************************************ 
 *sound card aatribute setting by Timebomb 
 ************************************************
 */ 

void scOptions(w, cli, call)
Widget w;
XtPointer cli;
XtPointer call;
{
  Widget formDialog;
  Widget form, bForm;
  Widget wi;
  Arg args[6];
  int n = 0;
  int mixer;
  int val;
  char str[20];

  if (scOpen)
    return;

  if ((mixer = open("/dev/mixer", O_RDWR)) < 0){
    wprint("Error opening /dev/mixer.\n");
    return;
  }

  XtSetArg(args[0], XmNtitle, "Sound Card Settings");
  formDialog = XmCreateFormDialog(toplevel, "scDialog", args, 1);
  form = XmCreateForm(formDialog, "addForm", NULL, 0);

  if (ioctl(mixer, MIXER_READ(MIC), &val) == -1){
    wprint("Error reading /dev/mixer.\n");
     return;
  }

  if (val > 99)
    val = 99;
  if (val < 0)
    val = 0;
  sprintf(str, "Mic: %d", val);

  mic = XtVaCreateManagedWidget("micLabel", xmLabelWidgetClass, form,
				XmNlabelString,XmStringCreateSimple(str),
				NULL);

  wi = XtVaCreateManagedWidget("mic", xmScrollBarWidgetClass, form,
			       XmNtopAttachment, XmATTACH_WIDGET,
			       XmNtopWidget, mic,
			       XmNorientation, XmHORIZONTAL,
			       NULL);

  XmScrollBarSetValues(wi, val, 1, 1, 0, True);
  XtAddCallback(wi, XmNdragCallback, sliderCB, (XtPointer) MIC);
  XtAddCallback(wi, XmNvalueChangedCallback, sliderCB, (XtPointer) MIC);

  if (ioctl(mixer, MIXER_READ(LINE), &val) == -1){
    wprint("Error reading /dev/mixer.\n");
    return;
  }
  if (val > 99)
    val = 99;
  if (val < 0)
    val = 0;
  sprintf(str, "Line: %d", val);
  line = XtVaCreateManagedWidget("lineLabel", xmLabelWidgetClass, form,
				 XmNlabelString, XmStringCreateSimple(str),
				 XmNtopAttachment, XmATTACH_WIDGET,
				 XmNtopWidget, wi,
				 NULL);

  wi = XtVaCreateManagedWidget("line", xmScrollBarWidgetClass, form,
			       XmNtopAttachment, XmATTACH_WIDGET,
			       XmNtopWidget, line,
			       XmNorientation, XmHORIZONTAL,
			       NULL);

  XmScrollBarSetValues(wi, val, 1, 1, 0, True);
  XtAddCallback(wi, XmNdragCallback, sliderCB, (XtPointer) LINE);
  XtAddCallback(wi, XmNvalueChangedCallback, sliderCB, (XtPointer) LINE);
  
  if (ioctl(mixer, MIXER_READ(VOL), &val) == -1){
    wprint("Error reading /dev/mixer.\n");
    return;
  }
  if (val > 99)
    val = 99;
  if (val < 0)
    val = 0;
  sprintf(str, "Volume: %d", val);
  vol = XtVaCreateManagedWidget("volLabel", xmLabelWidgetClass, form,
                                XmNlabelString, XmStringCreateSimple(str),
                                XmNtopAttachment, XmATTACH_WIDGET,
                                XmNtopWidget, wi,
				NULL);
  
  wi = XtVaCreateManagedWidget("vol", xmScrollBarWidgetClass, form,
			       XmNtopAttachment, XmATTACH_WIDGET,
			       XmNtopWidget, vol,
			       XmNorientation, XmHORIZONTAL,
			       NULL);

  XmScrollBarSetValues(wi, val, 1, 1, 0, True);
  XtAddCallback(wi, XmNdragCallback, sliderCB, (XtPointer) VOL);
  XtAddCallback(wi, XmNvalueChangedCallback, sliderCB, (XtPointer) VOL);

  wi = XtVaCreateManagedWidget("scDismiss", xmPushButtonWidgetClass, form,
			       XmNleftAttachment, XmATTACH_FORM,
			       XmNtopAttachment, XmATTACH_WIDGET,
			       XmNtopWidget, wi,
			       XmNlabelString, XmStringCreateSimple("Dismiss"),
			       NULL);
  
  XtAddCallback(wi, XmNactivateCallback, scDismiss, formDialog);
  XtManageChild(form);
  XtManageChild(formDialog);
  close(mixer);
  scOpen = 1;

}

void scDismiss(w, cli, call)
     Widget w;
     XtPointer cli;
     XmScrollBarCallbackStruct *call;
{
  scOpen = 0;
  XtDestroyWidget((Widget)cli);
}
 
void sliderCB(w, cli, call)
     Widget w;
     int cli;
     XmScrollBarCallbackStruct *call;
{
  char str[20];
  int mixer;
  int val;
  
  if ((mixer = open("/dev/mixer", O_RDWR)) < 0){
    wprint("Error opening /dev/mixer.\n");
    return;
  }
  
  val = call->value;
  
  switch(cli)
    {
    case MIC:
      sprintf(str, "Mic: %d", val);
      XtVaSetValues(mic,
		    XmNlabelString,  XmStringCreateSimple(str),
		    NULL);
      if (ioctl(mixer, MIXER_WRITE(MIC), &val) == -1){
	wprint("Error writing to /dev/mixer.\n");
	return;
      }

      break;
    case LINE:
      sprintf(str, "Line: %d", val);
      XtVaSetValues(line,
		    XmNlabelString,  XmStringCreateSimple(str),
		    NULL);
      if (ioctl(mixer, MIXER_WRITE(LINE), &val) == -1){
	wprint("Error writing to /dev/mixer.\n");
	return;
      }
      break;
    case VOL:
      sprintf(str, "Vol: %d", val);
      XtVaSetValues(vol,
		     XmNlabelString,  XmStringCreateSimple(str),
		     NULL);
      if (ioctl(mixer, MIXER_WRITE(VOL), &val) == -1){
	 wprint("Error writing to /dev/mixer.\n");
       return;
     }
      break;
    default:
      break;
    }
  close(mixer);
}


/*
 ***************************************
 * this sets/checks the status of the 
 * send audio file toggle switch
 * 1 if sending file, 0 if voice sample
 **************************************
 */

void toggled(w, client_data, state)
Widget w;
XtPointer client_data;
XmToggleButtonCallbackStruct *state;
{
  extern int send_a_file;
  extern Widget transmit;
  int current;
  current = state->set;

  if (current == 1 ) { 
    send_a_file = 1;
    wprint("File send mode enabled, voice sample disabled. \n");
    XtVaSetValues(transmit, XmNlabelString, 
		  XmStringCreateSimple("Press to transmit file"),
		  NULL);
  } else {
    send_a_file = 0;
    wprint("File send mode disabled, voice sampling resumed. \n");
    XtVaSetValues(transmit, XmNlabelString,
                  XmStringCreateSimple("Press to Record"),
                  NULL);
  }

}

void toggled2(w, client_data, state)
Widget w;
XtPointer client_data;
XmToggleButtonCallbackStruct *state;
{
  int current;
  current = state->set;

  if (current == 1 ) {
    wprint("Voice Mail logging enabled.\n");
    creat("/tmp/.ztalk_away",S_IRUSR);
  } else {
    wprint("Voice Mail logging disabled.\n");
    remove("/tmp/.ztalk_away");
  }

}


/*
 ***********************************
 * save list entries to file..
 ***********************************
*/

void save_rc()
{
  FILE *f;
  char fname[100];
  int i;
  
  sprintf(fname, "%s/.ztalkrc", getenv("HOME"));
  f = fopen(fname, "w");
  if (!f){
    wprint("Couldn't open %s for writing ... aborting save.\n", fname);
    return;
  }
  for (i = 0; i < hostCnt; i++){
    if (Nicks[i].nick){
      fprintf(f, "%s\t%s\n", Nicks[i].nick, Nicks[i].host);
    }
  }
  fprintf(f, "$\n");
  fclose(f);
  wprint("%s saved.\n", fname);
}

XtWorkProc record_proc()
{
  char TEMPstr[50];
  int temp;

  if (piped && !recording){
    if ((temp = read(pp[0], &TEMPstr[0], 50)) > 0){
      wprint(TEMPstr);
    }
  }
  if (recording == 1) {
    samps_read = read(audio,&buf_record[pos_record],1024);
    pos_record += samps_read;
  } else {
    usleep(2500); 
  }
}

/* 
 *****************************
 * send an audiofile...
 * create the file selection box 
 * that they can use to select files
 ****************************
*/
void au_file()
{
  Widget fs_box;

  Arg args[2];
  int n = 0;

  XtSetArg(args[n], XmNdirMask, XmStringCreateSimple(AU_PATH));n++;

  fs_box = XmCreateFileSelectionDialog(toplevel, "fs_box", args, n);
  XtAddCallback(fs_box, XmNcancelCallback, (void *) XtDestroyWidget, NULL);
  XtAddCallback(fs_box, XmNokCallback, send_file, NULL);
  XtSetSensitive(XmFileSelectionBoxGetChild(fs_box, XmDIALOG_HELP_BUTTON), 
		 False);
  XtManageChild(fs_box);
  
}

/*
 ******************************************
 * this is where the selected file from the 
 * file selectorbox is initialized
 ******************************************
 */  
void
send_file(fs, client_data, cbs)
Widget fs;
XtPointer client_data;
XmFileSelectionBoxCallbackStruct *cbs;
{

  char *filename;
  extern Widget audio_entry;
  XmString new_file;
  
  if (!XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &filename)) {
    wprint("Error in selecting file.\n");
    return;
  }

  if (!*filename) {
    wprint("No file selected.\n");
    XtFree(filename);
    return;
  }
  
  wprint("Filename selected: \"%s\"\n", filename);

  new_file = XmStringCreateSimple(new_file);
  XtVaSetValues(audio_entry, XmNvalue, filename, NULL);

  XtDestroyWidget(fs);;
  XmStringFree(new_file);
  XtFree(filename);
  
}

/*
 ***************************************************************************
 * Pop up a dialog that has 2 text fields in it ... on for the nickname
 * and one for the hostname to connect to. 
 ***************************************************************************
 */

void addHost(w, cli, call)
     Widget w;
     XtPointer cli;
     XtPointer call;
{
  Widget formDialog;
  Widget form, bForm;
  Widget l1, l2;
  Widget okB, cancelB;
/*  Widget sep;*/
 
  Arg args[8];
  int n = 0;
  
  formDialog = XmCreateFormDialog(toplevel, "addDialog", NULL, 0);
/*  form = XmCreateForm(formDialog, "addForm", NULL, 0);*/
  form = XtVaCreateWidget("addForm", xmFormWidgetClass, formDialog, 
			XmNfractionBase, 10, NULL); 

  XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  XtSetArg(args[n], XmNtopPosition, 1);n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNlabelString, 
	   XmStringCreateSimple("Nickname for host:"));n++;
  l1 = XmCreateLabelGadget(form, "label1", args, n);
  n = 0;

  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);n++;
  XtSetArg(args[n], XmNtopWidget, l1);n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);n++;
  XtSetArg(args[n], XmNleftPosition, 1);n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);n++;
  XtSetArg(args[n], XmNrightPosition, 9); n++;
  t1 = XmCreateText(form, "text1", args, n);
  n = 0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);n++;
  XtSetArg(args[n], XmNtopWidget, t1);n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);n++;
  XtSetArg(args[n], XmNlabelString, XmStringCreateSimple("Hostname:"));n++;
  l2 = XmCreateLabelGadget(form, "label2", args, n);n++;
  n = 0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);n++;
  XtSetArg(args[n], XmNtopWidget, l2);n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);n++;
  XtSetArg(args[n], XmNleftPosition, 1);n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);n++;
  XtSetArg(args[n], XmNrightPosition, 9); n++;
  t2 = XmCreateText(form, "text2", args, n);

  n=0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);n++;
  XtSetArg(args[n], XmNtopWidget, t2); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION);n++;
  XtSetArg(args[n], XmNleftPosition, 0);n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION);n++;
  XtSetArg(args[n], XmNrightPosition, 10); n++;
/*  XtSetArg(args[n], XmNborderWidth, 20); n++;*/
/*  sep = XmCreateSeparator(form, "sep", args, n);*/

  n = 0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);n++;
  XtSetArg(args[n], XmNtopWidget, t2);n++;
  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION);n++;
  XtSetArg(args[n], XmNbottomPosition, 9); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);n++;
  XtSetArg(args[n], XmNfractionBase, 10);n++;
    bForm = XmCreateForm(form, "bForm", args, n);

  okB = XtVaCreateManagedWidget("formDOK", xmPushButtonWidgetClass, bForm,
				XmNtopAttachment, XmATTACH_POSITION,
				XmNtopPosition, 4,
				XmNlabelString, XmStringCreateSimple("Ok"),
				XmNleftAttachment, XmATTACH_POSITION,
				XmNleftPosition, 1, 
				XmNrightAttachment, XmATTACH_POSITION,
				XmNrightPosition, 4,
				NULL);

  cancelB = XtVaCreateManagedWidget("formDCancel", xmPushButtonWidgetClass,
				    bForm,
				    XmNtopAttachment, XmATTACH_POSITION,
				    XmNtopPosition, 4,
				    XmNlabelString, XmStringCreateSimple("Cancel"),
				    XmNleftAttachment, XmATTACH_POSITION,
				    XmNleftPosition, 6,
				    XmNrightAttachment, XmATTACH_POSITION,
				    XmNrightPosition, 9,
				    NULL);


  XtAddCallback(okB, XmNactivateCallback, addOkCB, (XtPointer) formDialog);
  XtAddCallback(cancelB, XmNactivateCallback, addCancelCB, (XtPointer)formDialog);
  XtManageChild(t1);
  XtManageChild(l1);
  XtManageChild(t2);
  XtManageChild(l2);
  XtManageChild(form);
/*  XtManageChild(sep);*/
  XtManageChild(bForm);
  XtManageChild(formDialog);
}

void addOkCB(w, cli, call)
     Widget w;
     XtPointer cli;
     XtPointer call;
{
  char *n, *h;
  int pos;
  
  n = XmTextGetString(t1);
  h = XmTextGetString(t2);

  if (n && h){
    pos = addHostEntry(n, h);
    if (pos > -1){
      wprint("user: %s at host %s added.\n", n, h);
      XmListAddItem(list_w, XmStringCreateSimple(n), pos+1);
    } else {
      wprint("Too many nickanames!\n");
    }
  }
  XtDestroyWidget(cli);
}
void addCancelCB(w, cli, call)
     Widget w;
     XtPointer cli;
     XtPointer call;
{
  XtDestroyWidget(cli);
}

void deleteUser(w, cli, call)
     Widget w;
     XtPointer cli;
     XtPointer call;
{
  int *sel, n, pos = 0;
  
  if (!XmListGetSelectedPos (list_w, &sel, &n))
    return;
  /* Must delete in reverse order or positions get messed up! */
  while (n--){
    XmListDeletePos (list_w, sel[n]);
    pos = findEntry(sel[n]);
    deleteHostEntry(Nicks[pos].nick);
    XmTextSetString(to_who, "");
  }
}

int findEntry(int n)
{
  int found = 0, i = 0;

  while (found < n){
    if (Nicks[i].nick == NULL){
      ++i;
    } else {
      ++found;
      ++i;
    }
  }
  return i - 1;
}

/*
 **************************************** 
 * add_user() -- add an address to the list of recipients.
 * The user clicked on either Add or Delete buttons, or he hit return in
 * the To: text field.  In the latter case, client data is the add_btn,
 * so call that widget's ArmAndActivate() action proc.
 ***************************************
 */

void
add_user(w, client_data, call_data)
     Widget w;
     XtPointer client_data;
     XtPointer call_data;
{

  int data = (int) client_data;
  
  if (w == to_who) {
    /* User hit return... make it look as tho he clicked on Add */
/*    XtCallActionProc (data, "ArmAndActivate", cbs->event, NULL, 0);*/
    return;
  }
  
  /* User clicked on Add if data == 1, or delete otherwise */
  if (data) {
    /* get the value of the To: text widget */
    


    char *text = XmTextGetString (to_who);
    XmString str = XmStringCreateLocalized (text);
    /* if not a null string, add to List */
    if (text && *text) { 
      /* add to list */
      XmListAddItemUnselected (list_w, str, 0);
    }
    XmStringFree (str);
    XtFree (text);
    XmTextSetString (to_who, NULL); /* reset so user can add more */
  } 
  else {
    /* user clicked on Delete; delete all selected names */
    int *sel, n;
    if (!XmListGetSelectedPos (list_w, &sel, &n))
      return;
    /* Must delete in reverse order or positions get messed up! */
    while (n--)
      XmListDeletePos (list_w, sel[n]);
  }
}


/*
 ********************************************
 * add_to_to() -- callback for double-clicking a list item that 
 * causes the selected item to be added to To: text.  Now
 * the user can edit the address. 
 ******************************************
 */
void
add_to_to(list_w, client_data, call_data)
     Widget list_w;
     XtPointer client_data;
     XtPointer call_data;
{
  Widget to_who = (Widget) client_data;
  XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data;
  char *text;
  
  XmStringGetLtoR (cbs->item, XmFONTLIST_DEFAULT_TAG, &text);
  XmTextSetString (to_who, text);
  XmTextSetInsertionPosition (to_who, strlen(text));
  wprint("%s selected as recipient.\n",text);
  XtFree (text);
  XmProcessTraversal (list_w, XmTRAVERSE_NEXT_TAB_GROUP);
}

char *findHostEntry(char *n){
  int i;

  for (i = 0; i < hostCnt; i++){
    if (Nicks[i].nick && !strcmp(n, Nicks[i].nick)){
      return Nicks[i].host;
    }
  }
  return NULL;
}

/*
 ***********************************
 * Delete entry from list.
 *********************************** 
 */
void deleteHostEntry(char *n){
  int i;

  for (i = 0; i < hostCnt; i++){
    if (Nicks[i].nick && !strcmp(n, Nicks[i].nick)){
      wprint("Nickname \"%s\" at host %s deleted\n", Nicks[i].nick,
	     Nicks[i].host);
      Nicks[i].nick = NULL;
      Nicks[i].host = NULL;
      return;
    }
  }
}

/*
 ***********************************
 * Add host to list.
 ***********************************
 */

int addHostEntry(char *n, char *h)
{
  int i;

  for (i = 0; i < hostCnt; i++){
    if (Nicks[i].nick == NULL){
      Nicks[i].nick = (char *) malloc(strlen(n) + 1);
      strcpy(Nicks[i].nick, n);
      Nicks[i].host = (char *) malloc(strlen(h) + 1);
      strcpy(Nicks[i].host, h);
      return i;
    }
  }

  ++hostCnt;
  if (hostCnt > MAX_NICKS){
    --hostCnt;
    wprint("Too many hosts in host list.\n");
    return -1;
  }
  Nicks[hostCnt].nick = (char *) malloc(strlen(n) + 1);
  strcpy(Nicks[hostCnt].nick, n);
  Nicks[hostCnt].host = (char *) malloc(strlen(h) + 1);
  strcpy(Nicks[hostCnt].host, h);
  ++hostCnt;
  return hostCnt;
}


/*
 ***************************************** 
 * do_transmit() -- callback for when the user hits
 * the 'record/stop record' button. Determines if a 
 * file or sample is to be transfered
 *****************************************
 */
int 
do_transmit(viewport, client_data, call_data)
     Widget viewport;
     XtPointer client_data;
     XtPointer call_data;
{
  extern METHOD method;
  extern int     samps_read;           /* samples read from (/dev) AUDIO */
  extern int     audio;                /* handle to audio device */
  extern int     stat_compressor;      /* status from compressor call */
  extern int     stat_transmit;        /* status from transmit cal */
  extern int     size_send;            /* send buffer size */
  char *p, *r;
  char *tmp;
  char *nHost;
  char *recip;

  unsigned char * buf_send = NULL;  /* pointer to transmit buffer */
  
  extern Widget transmit, audio_entry;
  extern int recording, send_a_file;

  XmString button_label;

  char *selected_file;

  int file;
  int pid = 0;
  
  stat_transmit = 0;
  stat_compressor = 0;

  /* check if sending a file is enabled...if so..we read it and send it... */
  selected_file = XmTextGetString(audio_entry);
  
  if ((send_a_file  == 1)) { 

    samps_read = 0;
    pos_record = 0;

    wprint("opening file for transmit: %s\n", selected_file);
    
    /* read the selected file into buffer */
    file = open(selected_file,O_RDONLY);
    do {
      samps_read = read(file,&buf_record[pos_record],1024);
      if(samps_read < 0) continue;
      pos_record += samps_read;
    } while(samps_read);
    close(file);

    XtFree(selected_file);
    wprint("Audio file read and closed.\n");
    
  } else if ((recording == 1) && (send_a_file == 0)) {
  
    wprint(">>>STOPPING RECORD.\n");

    recording = 0;
    button_label = XmStringCreateSimple("Press to Record");
    XtVaSetValues(transmit, XmNlabelString, button_label, NULL);
    close(audio);
 
    wprint("Audio device closed.\n");
    XmStringFree(button_label);

  } else if ((recording == 0) && (send_a_file == 0)) {

    wprint(">>>RECORDING\n");
    pos_record = 0;
    samps_read = 0;
    recording = 1;
    button_label = XmStringCreateSimple("Recording...press to stop");
    XtVaSetValues(transmit, XmNlabelString, button_label, NULL);

    audio = open(AUDIO,O_RDONLY);
    wprint("Audio device opened.\n");

    XmStringFree(button_label);
    return(0);
  }
  if (piped){
    close(pp[0]);
    close(pp[1]);
  }
  if (pipe(pp) < 0){
    wprint("Could not create IPC pipe ... aborting send\n");
    return;
  }
  
  if ((pid = fork()) == 0){
    char pMsg[25] = "Audio data transmitted\n";
    dup2(pp[1], 1);
    close(pp[1]);
    stat_compressor = compress_buffer(method,
				      buf_record, pos_record, &buf_send,
				      &size_send); 
    
    if (stat_compressor) yikes("compressor",stat_compressor);
    
    r = XmTextGetString(to_who);
    while(r){
      if (p = (char *) index(r, ',')){
	*p = '\0'; ++p; while(p && *p == ' ') ++p;
      }
      if (!(nHost = findHostEntry(r))) {
	nHost = r;
      }
      
      strcpy(host, nHost);
      
      stat_transmit = transmit_buffer( method, buf_send, size_send); 
      
      printf("%s\n", pMsg);
/*      write(pp[1], &pMsg[0], sizeof(pMsg) * strlen(pMsg));*/
      r = p;
    }
    close(pp[1]);
    if (buf_send != buf_record) free(buf_send);
    
    if (stat_transmit) yikes ("transmit failure",stat_transmit);
    fclose(stdout);
    _exit(0);
  } 

  piped = 1;
  fcntl(pp[0], F_SETFL, O_NONBLOCK);
  selected_file=NULL;
  samps_read=0;
  audio=-1;
  file=-1;
  stat_compressor = 0; 
  stat_transmit = 0;
  size_send = 0;          /* send buffer size */
  buf_send = NULL; 
  pos_record = 0;
  
  wprint("Done.\n");
  wprint("Ready.\n");
  XtFree(selected_file);

}

/*
 ********************************************
 * CreateLabeledTextForm() -- create a Form 
 * widget that has a label on the left and a 
 * Text widget to the right.  Attach perimeter 
 * edges to form.  
 *******************************************
 */
Widget
CreateLabeledTextForm(parent, label_name, text_name)
Widget parent;
char *label_name, *text_name;
{
  Widget form, label, ret;
  
  form = XtVaCreateWidget ("form", 
			   xmFormWidgetClass, parent,
			   XmNorientation,      XmHORIZONTAL,
			   NULL);
  label = XtVaCreateManagedWidget (label_name, 
				   xmLabelGadgetClass, form,
				   XmNleftAttachment,   XmATTACH_FORM,
				   XmNtopAttachment,    XmATTACH_FORM,
				   XmNbottomAttachment, XmATTACH_FORM,
				   NULL);
  ret = XtVaCreateManagedWidget (text_name, 
				 xmTextWidgetClass, form,
				 XmNleftAttachment,   XmATTACH_WIDGET,
				 XmNleftWidget,       label,
				 XmNtopAttachment,    XmATTACH_FORM,
				 XmNrightAttachment,  XmATTACH_FORM,
				 XmNbottomAttachment, XmATTACH_FORM,
				 NULL);
  XtManageChild (form);
  
  return ret;
}

/*
 *********************************************************************
 * ztalk modules 
 * These are pretty much taken as-is from the ztalk.c sourced
 * by Scott Doty. - lb
 ********************************************************************
 */
	

/* 
 * compress_buffer() -- compress bu -> buf_send, using
 *  METHOD method.
 */
int compress_buffer(	METHOD method,
			unsigned char *buf_record,
 			int size_record,
			unsigned char ** buf_send,
			int * size_send
		)
{
  int stat_retval = 0;
  int pos_send=0;		/* position in send buffer */
  int pos_record=0;	/* position in record buffer */
  int i = 0, ticker = 0;	/* spare indices */
  gsm_byte * buf_gsm = NULL;
  char str[100];
  char done[10] = "done\n";
  
  switch(method) {
  case ME_FULL: {
    *buf_send = buf_record;
    *size_send = size_record;
    break;
  }
  case ME_GSM: {
    gsm_signal g_samples[160];
    gsm gh = NULL;
    
    fprintf(stdout, "gsm: Compressing ...");
    fflush(stdout);
/*    write(pp[1], &meSTR[0], sizeof(meSTR)*strlen(meSTR));*/
    if(!(gh = gsm_create())) return (-2);
    
    *size_send = (size_record/5) + (size_record/16);
    buf_gsm = (gsm_byte *) malloc(*size_send);
    if(NULL == buf_gsm) return(-2);
    while(pos_record < size_record)
      { /* this gets a little hairy... */
	/* could also use optimization... */
	/* also, sorry about the nl's -- consider
	   the alternative.  8) */
	for( i = 0; i < 160; i++)
	  g_samples[i] =
	    (gsm_signal) U2S( 
			     (buf_record[pos_record+i]) 
			     );
	
	gsm_encode(	gh,
		   g_samples,
		   (buf_gsm + pos_send)
		   );
	pos_send+=33;
	pos_record+=160;
	
	ticker++;
	if (ticker > 31)	/* for impatient users :) */
	  {
	    ticker = 0;
	  }
      }
    gsm_destroy(gh);
    *buf_send = buf_gsm;
    *size_send = pos_send;
    printf("Done\n");
/*    write(pp[1], &done[0], strlen(done)*sizeof(done));*/
    break;
  }
    
  default:	stat_retval=-1;
  }
  return(stat_retval);
}

int transmit_buffer(METHOD method, unsigned char * bu, int cnt)
{
  int hd = -1;
  char out[512];
  char ostr[30];
  
#ifdef TERM
  char pp1[256];
  char port[256];
#endif
  void killit() {
    close(hd);
    exit(1);
  }
  
  signal(SIGINT, killit);        /* if aborted, close the stream   -fein- */
  /* first, check the method */

  if (method < 0 || method >= ME_UNSUPPORTED) return(-1);
/*  sprintf(ostr, "Connecting to: %s\n", host);*/
  sprintf(ostr, "Making connection to: %s", host);
  printf("%s\n", ostr);
/*  write(pp[1], "Making Connection:", 50);*/
  
#ifdef TERM
  
  /*  sprintf(port,"%d",TCP_PORT_ZTALK);*/

  if (XmTextGetString(term_port) == "") {
    sprintf(port,"%d",TCP_PORT_ZTALK);
  } else {
    sprintf(port,"%d",atoi(XmTextGetString(term_port)));
  }
  sprintf(pp1,"%s",host);

  if(strchr(pp1,':')==NULL) {
      strcat(pp1,":");
      strcat(pp1,port);
  }
  
/*  wprint("ztalk:making TERM connection to %s\n",pp1);*/
  
  if((hd = connect_server(0)) < 0) {
    perror("Couldn't open term socket\n");
    close(hd);
  }
  else if(send_command(hd, C_PORT, 0, "%s", pp1) < 0) {
/*    wprint("Could not make TERM connection to %s.\n", host);*/
    hd = -1;
  }  else send_command(hd, C_DUMB, 1, 0);
  
#else
  
  /* connect */
/*    hd = gl_tcp_open(host,NULL,TCP_PORT_ZTALK);*/

  if (XmTextGetString(term_port) == "") {
    hd = gl_tcp_open(host,NULL,TCP_PORT_ZTALK);
  } else {
    hd = gl_tcp_open(host,NULL,atoi(XmTextGetString(term_port)));
  }

#endif /* TERM */

  if (hd < 0) {
    sprintf(ostr, "Could not connect to: %s", host);
    printf("%s\n", ostr);
/*    write(pp[1], &ostr[0], strlen(ostr) * sizeof(ostr));*/
/*    wprint("ztalk: Unable to connect to %s\n",host);*/
    return; /* APB -- No sense in continuing on if we can't connect */
  }
  
 
  read_line(hd);	/* get opening banner */
  
  /* send type of data & size */
  sprintf(out,
	  "%c%d\n",
	  id_compression[method],
	  cnt);
  write(hd,out,strlen(out));
  
  /* get the reply */
  
  read_line(hd);
  
  
  /* transmit sound block */
  slow_write(hd,bu,cnt);
  sprintf(out,"0000\n");
  write(hd,out,strlen(out));
  
  /* close the connection */
  close(hd);
  return (0); 
}

gl_tcp_open(host, service,port)
     char *host;
     char *service;
     int port;
{
  struct in_addr adress;
/*  unsigned long ip_addr;*/
  int len;
  int fd, resvport;
  unsigned long inaddr;
  struct servent *sp;
  struct hostent *hp;
  
  bzero(( char *) &tcp_srv_addr, sizeof(tcp_srv_addr));
  tcp_srv_addr.sin_family = AF_INET;
  
  if (service != NULL)	{
    if (( sp = getservbyname(service,"tcp")) == NULL)	{
      return (-1);
    }
    tcp_serv_info = *sp;
    if (port > 0)
      tcp_srv_addr.sin_port = htons(port);
    else
      tcp_srv_addr.sin_port = sp->s_port;
  } 
  else	{
    if (port <= 0)	{
      great_errno = 101;
      return (-2);
    }
    tcp_srv_addr.sin_port = htons(port);
  }
  
  if ((inaddr = inet_addr(host)) != INADDR_NONE)	{
    bcopy((char *) &inaddr, (char *) &tcp_srv_addr.sin_addr,
	  sizeof(inaddr));
    bcopy((char *) &inaddr, (char *) &adress.s_addr,
	  sizeof(inaddr));
    tcp_host_info.h_name = NULL;
  }
  else	{
    if (( hp = gethostbyname(host)) == NULL)	{
      great_errno = 102;
      return (-3);	
    }
    tcp_host_info = *hp;
    bcopy(hp->h_addr, (char *) &tcp_srv_addr.sin_addr,
	  hp->h_length);
    bcopy(hp->h_addr, (char *) &adress.s_addr,
	  hp->h_length);
  }
  
  
  strcpy(current_ip,inet_ntoa(adress));
  
  if (port >= 0)	{
    if ((fd = socket(AF_INET, SOCK_STREAM,0)) < 0)	{
      great_errno = 108;
      return (-4);
    }
  }
  else if (port < 0)	{
    resvport = IPPORT_RESERVED -1;
    if (( fd = rresvport(&resvport) < 0))	{
      great_errno = 108;
      return (-5);
    }
  }
  alarm(60);
  if (connect(fd, (struct sockaddr *) &tcp_srv_addr,
	      sizeof(tcp_srv_addr)) < 0)	{
    close(fd);
    great_errno = 107;
    alarm(0);
    return (-6);
  }
  
  len = sizeof (myctladdr);
  if (getsockname(fd, (struct sockaddr *)&myctladdr, &len) < 0) {
    perror("ftp: getsockname");
    alarm(0);
    close(fd);
    return(-7);
  }
  alarm(0);
  return (fd);
}


slow_write(int hd,char *s,int sz)
{
  int pos;
  int a;
  int tz;
  
  pos = 0;
  tz = sz;  
  
  
  while (1){
    a = write(hd,&s[pos],tz);
    if (a < 0)	
      return (-1);
    pos +=a;
    tz -= a;
    if (pos >= sz)
      return (pos);
  }
  
}

read_line(hd)
{
  char c;
  char bu[100];
  char tstr[80];
  int a;
  
  a = 0;
  
  while (1)	{ 
    if (read(hd,&c,1)!= 1)
      break; 
    if (c == 10)
      break;
    bu[a++] = c;
  }
  bu[a] = '\0';
  sprintf(tstr, "<%s>", bu);
  printf("%s\n", tstr);
/*  write(pp[1], &tstr[0], sizeof(tstr) * strlen(tstr));*/
}

yikes (char * msg, int stat)
{
  wprint("ztalk error:%s returned %d\n",
	 msg,
	 stat
	  );
/*  exit(1);*/
}


/*
 ************************************
 * this neat function allows writing
 * to the main viewport as if you
 * we're using printf() to stdout
 ************************************
 */

void
wprint(va_alist)
     va_dcl
{
  extern Widget viewport;
  
  char msgbuf[BUFSIZ];
  char *fmt;
  static XmTextPosition wpr_position;
  va_list args;
  
  va_start(args);
  fmt = va_arg(args, char *);
  (void) vsprintf(msgbuf, fmt, args);
  
  va_end(args);
  XmTextInsert(viewport, wpr_position, msgbuf);
  wpr_position += strlen(msgbuf);
/*  XtVaSetValues(viewport, XmNcursorPosition, wpr_position, NULL);*/
  XmTextShowPosition(viewport, wpr_position);

}

/*
 ***************************************************************************
 * Open up the /tmp/vmail directory, get lising of all avaialable voice
 * mail message, stick em in a listbox and allow the user to play/delete
 * them.
 ***************************************************************************
 */

void vmPlayCB(w, cli, call)
     Widget w;
     XtPointer cli;
     XtPointer call;
{
  DIR *d;
  struct dirent *entry;
  struct dirent *t;
  Widget fDialog;
  Widget label;
  Widget form;
  Widget playB;
  Widget deleteB;
  Widget dismissB;
  Widget rc;
  Widget sep;
  Arg args[10];
  int n = 0;

/*  XtSetArg(args[0], XmNtitle, XmStringCreateSimple("Voice Mail Files"));*/

  if (amOpen)
    return;

  d = opendir("/tmp/vmail");

  if (!d){
    wprint("Whoops ... /tmp/vmail doesn't exist, or is unreadable.\n");
    return;
  }

  while ((t = readdir(d)) && t->d_name[0] == '.');
  
  if (t == NULL){
    wprint("You have no messages in /tmp/vmail\n");
    return;
  }

  amOpen = 1;

  fDialog = XmCreateFormDialog(toplevel, "vmDialog", args, 1);

  form = XmCreateForm(fDialog, "vmForm", NULL, 0);

  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNlabelString, XmStringCreateSimple("Voice Mail")); n++;

  label = XmCreateLabel(form, "label", args, n);

  n = 0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  XtSetArg(args[n], XmNtopWidget, label); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
/*  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;*/
  XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
  XtSetArg(args[n], XmNvisibleItemCount, 5); ++n;
  XtSetArg(args[n], XmNselectionPolicy, XmEXTENDED_SELECT); n++;
  XtSetArg(args[n], XmNlistSizePolicy, XmRESIZE_IF_POSSIBLE); n++;
  lb = XmCreateScrolledList(form, "vmListBox", args, n);

  XtAddCallback(lb, XmNsingleSelectionCallback, mailMessageSet, NULL);
  XtAddCallback(lb, XmNmultipleSelectionCallback, mailMessageSet, NULL);
  XtAddCallback(lb, XmNdefaultActionCallback, playMailMessage, NULL);
  XtAddCallback(lb, XmNbrowseSelectionCallback, mailMessageSet, NULL);
  XtAddCallback(lb, XmNextendedSelectionCallback, mailMessageSet, NULL);
  
  n=0;
  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET);n++;
  XtSetArg(args[n], XmNtopWidget, lb); n++;
  XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM);n++;
  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM);n++;
  /*  XtSetArg(args[n], XmNborderWidth, 20); n++;*/
  sep = XmCreateSeparator(form, "sep", args, n);

  
/*  rc = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass, form,
			       XmNorientation, XmHORIZONTAL,
			       XmNtopAttachment, XmATTACH_WIDGET,
			       XmNtopWidget, lb,
			       NULL);*/
  rc = XtVaCreateManagedWidget("rc", xmFormWidgetClass, form,
			       XmNtopAttachment, XmATTACH_WIDGET,
			       XmNtopWidget, lb,
			       XmNbottomOffset, 20,
			       XmNfractionBase, 10,
			       NULL);
			       

  playB = XtVaCreateManagedWidget("playB", xmPushButtonWidgetClass, rc,
				  XmNlabelString, XmStringCreateSimple("Play"),
/*				  XmNwidth, 40,*/
				  XmNtopAttachment, XmATTACH_POSITION,
				  XmNtopPosition, 4,
				  XmNleftAttachment, XmATTACH_POSITION,
				  XmNleftPosition, 1,
				  XmNrightAttachment, XmATTACH_POSITION,
				  XmNrightPosition, 3,
				  NULL);

  XtAddCallback(playB, XmNactivateCallback, playMailMessage, (XtPointer)0);
  
  deleteB = XtVaCreateManagedWidget("deleteB", xmPushButtonWidgetClass, rc,
				    XmNlabelString,
				    XmStringCreateSimple("Delete"),
/*				    XmNwidth, 40,*/
				    XmNtopAttachment, XmATTACH_POSITION,
				    XmNtopPosition, 4,
				    XmNleftAttachment, XmATTACH_POSITION,
				    XmNleftPosition, 4,
				    XmNrightAttachment, XmATTACH_POSITION,
				    XmNrightPosition, 6,
				    NULL);

  XtAddCallback(deleteB, XmNactivateCallback, playMailMessage, (XtPointer)1);

  dismissB = XtVaCreateManagedWidget("dismissB", xmPushButtonWidgetClass, rc,
				     XmNlabelString,
				     XmStringCreateSimple("Dismiss"),
/*				     XmNwidth, 40,*/
				     XmNtopAttachment, XmATTACH_POSITION,
				     XmNtopPosition, 4,
				     XmNleftAttachment, XmATTACH_POSITION,
				     XmNleftPosition, 7,
				     XmNrightAttachment, XmATTACH_POSITION,
				     XmNrightPosition, 9,
				     NULL);

  XtAddCallback(dismissB, XmNactivateCallback, playMailMessage, (XtPointer)fDialog);


  XtManageChild(label);
  XtManageChild(sep);
  XtManageChild(lb);
  XtManageChild(form);
  XtManageChild(fDialog);
  
  for (entry = t; entry; entry = readdir(d)){
    if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
      XmListAddItemUnselected(lb, XmStringCreateSimple(entry->d_name), 0);
  }
  XtVaSetValues(fDialog, XmNtitle, XmStringCreateSimple("Answering Machine"));
}

void mailMessageSet(w, cli, call)
     Widget w;
     XtPointer cli;
     XmListCallbackStruct *call;
{
  int i;
  char *text;

  MailMessages[0] = '\0';
  if (call->selected_item_count != 1){
    for(i = 0; i < call->selected_item_count; i++){
      XmStringGetLtoR (call->selected_items[i], XmFONTLIST_DEFAULT_TAG, &text);
      if (i != 0) strcat(MailMessages, ",");
      strcat(MailMessages, text);
    }
  } else {
    XmStringGetLtoR (call->item, XmFONTLIST_DEFAULT_TAG, &text);
    strcpy(MailMessages, text);
  }
}

void playMailMessage(w, cli, call)
     Widget w;
     int cli;
     XtPointer call;
{
  int i;
  char *p, *l;
  int f;
  int samps_read;
  int audio;
  
  if (cli == 0){
    char lMessages[BUFSIZ];
    char file[100];

    strcpy(lMessages, MailMessages);
    l = lMessages;
    while (l){
      if (p = (char *) index(l, ',')){
	*p = '\0'; ++p; while(p && *p == ' ') ++p;
      }
      wprint("Playing message: %s\n", l);
      sprintf(file, "/tmp/vmail/%s", l);
      f = open(file, O_RDONLY);
      pos_record = 0;
      do {
	samps_read = read(f, &buf_record[pos_record], 1024);
	if(samps_read < 0) continue;
	pos_record += samps_read;
      } while(samps_read);
      close(f);
      audio = open("/dev/audio",O_WRONLY);
      if (audio < 0){
	wprint("Error opening /dev/audio for writing.\n");
	return;
      }
      write(audio, buf_record, pos_record);
      close(audio);
      l = p;
    }
  } else if (cli == 1){
    char file[100];
    
    l = MailMessages;
    while(l){
      if (p = (char *) index(l, ',')){
	*p = '\0'; ++p; while(p && *p == ' ') ++p;
      }
      sprintf(file, "/tmp/vmail/%s", l);
      if (unlink(file) < 0){
	wprint("You do not have permission to delete %s\n", file);
      } else {
	XmListDeleteItem(lb, XmStringCreateSimple(l));
	wprint("Message %s deleted\n", l);
      }
      l = p;
    }
    MailMessages[0] = '\0';
  } else {
    XtDestroyWidget((Widget) cli);
    MailMessages[0] = '\0';
    amOpen = 0;
  }
}


void setRecipients(w, cli, call)
     Widget w;
     XtPointer cli;
     XmListCallbackStruct *call;
{
  int i;
  char *text;
  
  Recipients[0] = '\0';
  if (call->selected_item_count != 1){
    for(i = 0; i < call->selected_item_count; i++){
      XmStringGetLtoR (call->selected_items[i], XmFONTLIST_DEFAULT_TAG, &text);
      if (i != 0)
	strcat(Recipients, ",");
      strcat(Recipients, text);
    }
    XmTextSetString(to_who, Recipients);
  } else {
    XmStringGetLtoR (call->item, XmFONTLIST_DEFAULT_TAG, &text);
    strcpy(Recipients, text);
    XmTextSetString (to_who, text);
  } 
}

/*
 **************************
 * read in an XPM pixmap, thanks OKI
 **************************
 */

#ifdef XPM
Pixmap ReadXPM(char *filename)
{
  Display *dpy;
  int screen;
  Window root;
  Pixmap rootXpm;
  Pixmap temp;
  XWindowAttributes root_attr;
  XpmAttributes xpm_attributes;
  int val;

  dpy = XtDisplay(toplevel);
  screen = DefaultScreen(dpy);
  root = RootWindow(dpy, screen);
  XGetWindowAttributes(dpy,root,&root_attr); 
  xpm_attributes.colormap = root_attr.colormap;
  xpm_attributes.valuemask = XpmSize | XpmReturnPixels|XpmColormap | XpmVisual;

  if((val = XpmReadFileToPixmap(dpy,root, filename,
                                &rootXpm, &temp,
                                &xpm_attributes))!= XpmSuccess)

/*    if(XpmReadFileToPixmap(dpy, Root, path,
			   &Buttons[button].iconPixmap,
			   &Buttons[button].icon_maskPixmap, 
			   &xpm_attributes) == XpmSuccess) */
   
    {
        if(val == XpmOpenFailed)
          fprintf(stderr, "Couldn't open pixmap file %s\n", filename);
        else if(val == XpmColorFailed)
          fprintf(stderr, "Couldn't allocated required colors\n");
        else if(val == XpmFileInvalid)
         fprintf(stderr, "Invalid Format for an Xpm File\n");
        else if(val == XpmColorError)
          fprintf(stderr, "Invalid Color specified in Xpm FIle\n");
        else if(val == XpmNoMemory)
          fprintf(stderr, "Insufficient Memory\n");
       return XmUNSPECIFIED_PIXMAP;
      }

   return(rootXpm);
}
#endif










