/*
* GTK ASTerisk MANager
* Copyright (C) 2002, Digium
*
* Written by Mark Spencer <markster@digium.com>
*
* Distributed under GNU GPL
*
* All Rights Reserved
*/
#ifndef _WIN32
#ifdef __FreeBSD__
#include <sys/types.h>
#endif
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>
#else
#include <winsock.h>
#include "win32dep.h"
#endif
#include <stdio.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>
#include <glib.h>
#include <time.h>
#include "gastman.h"
#include <asterisk/manager.h>
#include <asterisk/md5.h>
#define MAX_HEADERS 256
#define MAX_LEN 1024
#define CHAN_MAGIC 0xc649
#define EXTEN_MAGIC 0x3539
#define TRASH_MAGIC 0x7945
#define QUEUE_MAGIC 0x053b
#define QUEUENAME_MAGIC 0x67a4
#define MAX_HIST 1000
static char *history[MAX_HIST];
static int maxhist;
static int curhistpos;
static void shrink_hist(void)
{
int x;
if (history[0])
free(history[0]);
for (x=0;x<maxhist - 1;x++)
history[x] = history[x + 1];
history[x] = NULL;
maxhist--;
if (curhistpos > maxhist)
maxhist = curhistpos;
}
static void hist_append(const char *s)
{
if (maxhist >= MAX_HIST - 1)
shrink_hist();
curhistpos = maxhist;
history[curhistpos] = strdup(s);
maxhist++;
curhistpos = maxhist;
}
static struct mansession {
struct sockaddr_in sin;
int fd;
char inbuf[MAX_LEN];
int inlen;
} session;
struct message {
int hdrcount;
int gettingdata;
char headers[MAX_HEADERS][MAX_LEN];
} message;
static struct ast_chan {
int magic;
char name[80];
char exten[20];
char context[20];
char priority[20];
char callerid[40];
char icon[80];
char state[10];
char ident[80];
char link[80];
struct gui_object *obj;
struct gui_object *eobj;
struct ast_chan *next;
} *chans;
static struct ast_exten {
int magic;
char name[256];
char extens[256];
char chans[256];
char icon[80];
char ident[80];
char label[80];
int activechan;
struct gui_object *obj;
struct ast_exten *next;
} *extens;
static struct ast_queue {
int magic;
char name[256];
char icon[80];
char callerid[256];
char queue[256];
int position;
time_t start;
struct gui_queue *obj;
struct ast_queue *next;
} *queues;
static struct ast_queuename {
int magic;
char name[256];
int current;
int max;
struct gui_queue *obj;
struct ast_queuename *next;
} *queuenames;
static struct ast_wastebasket {
int magic;
} wastebasket = { TRASH_MAGIC };
static struct ast_chan *current = NULL;
static struct ast_queue *currentq = NULL;
static char curhost[256];
static int debug = 0;
static int chan_match(char *real, char *pat)
{
char copy[80];
char tech[80];
char *s;
strncpy(copy, real, sizeof(copy));
strncpy(tech, real, sizeof(copy));
s = strchr(tech, '/');
if (s)
*s = '\0';
if (!strcasecmp(tech, "Zap")) {
/* Zap Channel, match before - */
s = strchr(copy, '-');
if (s)
*s = '\0';
if (!strcmp(pat, copy))
return 1;
} else if (!strcasecmp(tech, "Asyncgoto")) {
/* Not going to match for sure */
return 0;
} else if (!strcasecmp(tech, "Agent")) {
if (!strcasecmp(pat, copy))
return 1;
return 0;
} else if (!strcasecmp(tech, "Phone")) {
if (!strcasecmp(pat, copy))
return 1;
return 0;
} else if (!strcasecmp(tech, "Console")) {
if (!strcasecmp(pat, copy))
return 1;
return 0;
} else if (!strcasecmp(tech, "OSS")) {
if (!strcasecmp(pat, copy))
return 1;
return 0;
} else if (!strncasecmp(tech, "IAX[", 4)) {
s = strchr(copy, '/');
if (s)
*s = '\0';
if (!strcasecmp(pat, copy)) {
return 1;
}
} else if (!strncasecmp(tech, "IAX/", 4)) {
s = strchr(copy, '/');
if (s)
*s = '\0';
if (!strcasecmp(pat, copy)) {
return 1;
}
} else if (!strncasecmp(tech, "SIP", 3)) {
/* SIP Channel, match before - */
s = strchr(copy, '-');
if (s)
*s = '\0';
if (!strcmp(pat, copy))
return 1;
} else if (!strncasecmp(tech, "Local", 5)) {
/* Local Channel, match before - */
s = strchr(copy, '-');
if (s)
*s = '\0';
if (!strcmp(pat, copy))
return 1;
} else if (!strncasecmp(tech, "H323", 4)) {
/* H323 Channel, match before : */
s = strchr(copy, ':');
if (s)
*s = '\0';
if (!strncmp(pat, copy, strlen(pat)))
return 1;
} else {
fprintf(stderr, "Dunno how to tell if %s is %s\n", real, pat);
}
return 0;
}
static int ast_extension_match(char *pattern, char *data)
{
int match;
/* If they're the same return */
if (!strcasecmp(pattern, data))
return 1;
/* All patterns begin with _ */
if (pattern[0] != '_')
return 0;
/* Start optimistic */
match=1;
pattern++;
while(match && *data && *pattern && (*pattern != '/')) {
switch(toupper(*pattern)) {
case 'N':
if ((*data < '2') || (*data > '9'))
match=0;
break;
case 'X':
if ((*data < '0') || (*data > '9'))
match = 0;
break;
case '.':
/* Must match */
return 1;
case ' ':
case '-':
/* Ignore these characters */
data--;
break;
default:
if (*data != *pattern)
match =0;
}
data++;
pattern++;
}
/* Must be at the end of both */
if (*data || (*pattern && (*pattern != '/')))
match = 0;
return match;
}
static struct ast_exten *exten_match(char *exten, char *context)
{
struct ast_exten *cur;
char tmp[256], *con, *cure;
cur = extens;
while(cur) {
strncpy(tmp, cur->extens, sizeof(tmp) - 1);
cure = strtok(tmp, ",");
while (cure) {
while((*cure < 33) && *cure) cure++;
con = strchr(cure, '@');
if (con) {
*con = '\0';
con++;
}
if (ast_extension_match(cure, exten) && (!con || !strcasecmp(context, con)))
return cur;
cure = strtok(NULL, ",");
}
cur = cur->next;
}
return NULL;
}
static char *find_icon_by_channel(char *name)
{
struct ast_exten *cur;
char tmp[256], *c;
cur = extens;
while(cur) {
strncpy(tmp, cur->chans, sizeof(tmp) - 1);
c = strtok(tmp, ",");
while(c) {
while(*c && (*c < 33))
c++;
if (chan_match(name, c))
return cur->icon;
c = strtok(NULL, ",");
}
cur = cur->next;
}
if (rand() & 1024)
return "manonphone";
else
return "womanonphone";
}
static void check_extens(void)
{
/* XXX This should be done much more efficiently */
struct ast_chan *curchan;
struct ast_exten *curext;
char tmp[256], *c;
curext = extens;
while(curext) {
curext->activechan = 0;
curext = curext->next;
}
curext = extens;
while(curext) {
curchan = chans;
strncpy(tmp, curext->chans, sizeof(tmp) - 1);
c = strtok(tmp, ",");
while(c) {
while(*c && (*c < 33))
c++;
curchan = chans;
while(curchan) {
if (chan_match(curchan->name, c)) {
curext->activechan = 1;
break;
}
curchan = curchan->next;
}
if (curext->activechan)
break;
c = strtok(NULL, ",");
}
curext = curext->next;
}
curext = extens;
while(curext) {
gui_object_set_led(curext->obj, curext->activechan);
curext = curext->next;
}
}
static struct ast_queuename *find_queuename(char *name);
static struct ast_queue *find_queue(char *name, char *queuen)
{
struct ast_queue *prev = NULL, *queue = queues;
struct ast_queuename *qn;
char *icon;
if (!strlen(name))
return NULL;
while(queue) {
if (!strcmp(name, queue->name))
return queue;
prev = queue;
queue = queue->next;
}
queue = malloc(sizeof(struct ast_queue));
if (queue) {
icon = find_icon_by_channel(name);
memset(queue, 0, sizeof(struct ast_queue));
strncpy(queue->name, name, sizeof(queue->name) - 1);
strncpy(queue->queue, queuen, sizeof(queue->queue) - 1);
queue->magic = QUEUE_MAGIC;
strncpy(queue->icon, icon, sizeof(queue->icon) - 1);
queue->obj = gui_add_queue(name, queuen, icon, queue, TYPE_QUEUE);
if (prev)
prev->next = queue;
else
queues = queue;
qn = find_queuename(queuen);
if (qn) {
qn->current++;
gui_queue_set_queueinfo(qn->obj, qn->current, qn->max);
}
}
return queue;
}
static struct ast_queuename *find_queuename(char *name)
{
struct ast_queuename *prev = NULL, *queue = queuenames;
if (!strlen(name))
return NULL;
while(queue) {
if (!strcmp(name, queue->name))
return queue;
prev = queue;
queue = queue->next;
}
queue = malloc(sizeof(struct ast_queuename));
if (queue) {
memset(queue, 0, sizeof(struct ast_queuename));
strncpy(queue->name, name, sizeof(queue->name) - 1);
queue->magic = QUEUENAME_MAGIC;
queue->obj = gui_add_queue(NULL, name, NULL, queue, TYPE_QUEUENAME);
if (prev)
prev->next = queue;
else
queuenames = queue;
}
return queue;
}
static struct ast_chan *find_chan(char *name)
{
struct ast_chan *prev = NULL, *chan = chans;
char *icon;
if (!strlen(name))
return NULL;
while(chan) {
if (!strcmp(name, chan->name))
return chan;
prev = chan;
chan = chan->next;
}
chan = malloc(sizeof(struct ast_chan));
if (chan) {
icon = find_icon_by_channel(name);
memset(chan, 0, sizeof(struct ast_chan));
strncpy(chan->name, name, sizeof(chan->name) - 1);
snprintf(chan->ident, sizeof(chan->ident), "[%s]chan[%s]", curhost, chan->name);
chan->magic = CHAN_MAGIC;
strncpy(chan->icon, icon, sizeof(chan->icon) - 1);
if (prev)
prev->next = chan;
else
chans = chan;
chan->obj = gui_add_object(name, name, icon, chan->ident, chan, 0, 0, TYPE_CALL);
}
check_extens();
return chan;
}
static void del_chan(char *name)
{
struct ast_chan *prev = NULL, *chan = chans;
while(chan) {
if (!strcmp(name, chan->name)) {
if (current == chan)
current = NULL;
if (prev)
prev->next = chan->next;
else
chans = chan->next;
gui_del_object(chan->obj);
chan->magic = 0;
free(chan);
check_extens();
return;
}
prev = chan;
chan = chan->next;
}
}
static void del_queue(char *name)
{
struct ast_queue *prev = NULL, *queue = queues;
struct ast_queuename *qn;
while(queue) {
if (!strcmp(name, queue->name)) {
qn = find_queuename(queue->queue);
if (qn) {
qn->current--;
gui_queue_set_queueinfo(qn->obj, qn->current, qn->max);
}
if (currentq == queue)
currentq = NULL;
if (prev)
prev->next = queue->next;
else
queues = queue->next;
gui_del_queue(queue->obj);
queue->magic = 0;
free(queue);
return;
}
prev = queue;
queue = queue->next;
}
}
static void fdprintf(int fd, char *fmt, ...)
{
char stuff[4096];
va_list ap;
va_start(ap, fmt);
vsnprintf(stuff, sizeof(stuff), fmt, ap);
va_end(ap);
#ifndef _WIN32
write(fd, stuff, strlen(stuff));
#else
send(fd, stuff, strlen(stuff), 0);
#endif
}
static char *get_header(struct message *m, char *var)
{
char cmp[80];
int x;
snprintf(cmp, sizeof(cmp), "%s: ", var);
for (x=0;x<m->hdrcount;x++)
if (!strncasecmp(cmp, m->headers[x], strlen(cmp)))
return m->headers[x] + strlen(cmp);
return "";
}
char *gastman_curhost(void)
{
return curhost;
}
static void update_channel(struct ast_chan *chan)
{
char tmp[1024] = "";
char tmp2[80];
struct ast_exten *ext;
struct gui_object *obj = NULL;
struct ast_chan *lchan = NULL;
if (strlen(chan->callerid)) {
snprintf(tmp2, sizeof(tmp2), "Caller: %s\n", chan->callerid);
strcat(tmp, tmp2);
}
if (strlen(chan->exten)) {
snprintf(tmp2, sizeof(tmp2), "At: %s@%s:%s\n", chan->exten, chan->context, chan->priority);
strcat(tmp, tmp2);
if (strlen(chan->name)) {
snprintf(tmp2, sizeof(tmp2), "Channel: %s\n", chan->name);
strcat(tmp, tmp2);
}
}
if (chan->obj != NULL)
gui_object_set_tooltip(chan->obj, tmp);
if (strlen(chan->exten))
snprintf(tmp, sizeof(tmp), "%s@%s:%s", chan->exten, chan->context, chan->priority);
else
strcpy(tmp, "");
if (strlen(chan->link))
lchan = find_chan(chan->link);
ext = exten_match(chan->exten, chan->context);
gui_object_set_callinfo(chan->obj, strlen(chan->callerid) ? chan->callerid : "<unknown>",
chan->link, tmp, lchan ? lchan->obj : NULL, ext ? ext->obj : NULL);
if (ext)
obj = ext->obj;
if (obj != chan->eobj) {
if (chan->eobj)
gui_unlink(chan->obj, chan->eobj);
chan->eobj = obj;
if (obj) {
gui_link(chan->obj, chan->eobj);
gui_move_near(chan->eobj, chan->obj);
}
}
/* Update location if appropriate */
if (current == chan)
gastman_object_select(current);
}
static void update_channels(void)
{
struct ast_chan *cur = chans;
while(cur) {
update_channel(cur);
cur = cur->next;
}
}
void gastman_queue_select(void *pvt)
{
struct ast_queue *q = pvt;
printf("Selected '%s', CID '%s', waiting for %ld seconds, position %d\n",
q->name, q->callerid, time(NULL) - q->start, q->position);
}
void gastman_object_select(void *pvt)
{
struct ast_chan *chan = pvt;
struct ast_exten *exten = pvt;
char tmp[1024] = "";
char tmp2[80];
char tmp3[80];
if (chan->magic == CHAN_MAGIC) {
if (strlen(chan->callerid))
snprintf(tmp2, sizeof(tmp2), "%s (%s)", chan->name, chan->callerid);
else
snprintf(tmp2, sizeof(tmp2), "%s", chan->name);
if (strlen(chan->exten))
snprintf(tmp3, sizeof(tmp3), " is at %s@%s:%s", chan->exten, chan->context, chan->priority);
else
strcpy(tmp3, "");
snprintf(tmp, sizeof(tmp), "%s%s", tmp2, tmp3);
} else if (chan->magic == EXTEN_MAGIC) {
snprintf(tmp, sizeof(tmp), "%s at Extension %s", exten->label, exten->name);
}
current = chan;
gui_status(tmp);
}
static int event_newstate(struct mansession *s, struct message *m)
{
struct ast_chan *chan;
char *callerid;
chan = find_chan(get_header(m, "Channel"));
callerid = get_header(m, "Callerid");
if (strlen(callerid))
strncpy(chan->callerid, callerid, sizeof(chan->callerid) - 1);
strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
update_channel(chan);
return 0;
}
static int event_newexten(struct mansession *s, struct message *m)
{
struct ast_chan *chan;
chan = find_chan(get_header(m, "Channel"));
strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
update_channel(chan);
return 0;
}
static int event_newchannel(struct mansession *s, struct message *m)
{
struct ast_chan *chan;
char tmp[256];
chan = find_chan(get_header(m, "Channel"));
strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
update_channel(chan);
if (strlen(chan->callerid))
snprintf(tmp, sizeof(tmp), "New channel %s from %s", chan->name, chan->callerid);
else
snprintf(tmp, sizeof(tmp), "New channel %s", chan->name);
gui_status(tmp);
return 0;
}
static int event_status(struct mansession *s, struct message *m)
{
struct ast_chan *chan, *chan2;
chan = find_chan(get_header(m, "Channel"));
strncpy(chan->state, get_header(m, "State"), sizeof(chan->state) - 1);
strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
strncpy(chan->exten, get_header(m, "Extension"), sizeof(chan->exten) - 1);
strncpy(chan->context, get_header(m, "Context"), sizeof(chan->context) - 1);
strncpy(chan->priority, get_header(m, "Priority"), sizeof(chan->priority) - 1);
strncpy(chan->link, get_header(m, "Link"), sizeof(chan->link) - 1);
if (strlen(chan->link) && (chan2 = find_chan(chan->link))) {
gui_link(chan->obj, chan2->obj);
}
update_channel(chan);
return 0;
}
static int event_newcallerid(struct mansession *s, struct message *m)
{
struct ast_chan *chan;
chan = find_chan(get_header(m, "Channel"));
strncpy(chan->callerid, get_header(m, "Callerid"), sizeof(chan->callerid) - 1);
update_channel(chan);
return 0;
}
static int event_hangup(struct mansession *s, struct message *m)
{
char *name = get_header(m, "Channel");
char tmp[80];
del_chan(name);
snprintf(tmp, sizeof(tmp), "%s hungup", name);
gui_status(tmp);
return 0;
}
static int event_ignore(struct mansession *s, struct message *m)
{
return 0;
}
static int event_rename(struct mansession *s, struct message *m)
{
struct ast_chan *chan, *chan2;
char *icon;
chan = find_chan(get_header(m, "Oldname"));
strncpy(chan->name, get_header(m, "Newname"), sizeof(chan->name) - 1);
#if 0
printf("%s is now %s\n", get_header(m, "Oldname"), get_header(m, "Newname"));
#endif
gui_object_set_text(chan->obj, chan->name);
/* Add object back after it changes names */
gui_del_object(chan->obj);
icon = find_icon_by_channel(chan->name);
if (icon)
strncpy(chan->icon, icon, sizeof(chan->icon) - 1);
chan->obj = gui_add_object(chan->name, chan->name, chan->icon, chan->ident, chan, 0, 0, TYPE_CALL);
update_channel(chan);
if (strlen(chan->link) && (chan2 = find_chan(chan->link))) {
gui_link(chan->obj, chan2->obj);
}
check_extens();
return 0;
}
static void alloc_exten(char *exten, char *chans, char *icon, char *label, int size, int x, int y)
{
struct ast_exten *cur;
char tmp[256];
cur = malloc(sizeof(struct ast_exten));
if (cur) {
memset(cur, 0, sizeof(struct ast_exten));
cur->magic = EXTEN_MAGIC;
strncpy(cur->name, exten, sizeof(cur->name) - 1);
strtok(cur->name, ",");
strncpy(cur->extens, exten, sizeof(cur->extens) - 1);
strncpy(cur->icon, icon, sizeof(cur->icon) - 1);
strncpy(cur->chans, chans, sizeof(cur->chans) - 1);
strncpy(cur->label, label, sizeof(cur->label) - 1);
snprintf(cur->ident, sizeof(cur->ident), "[%s]exten[%s:%s]", curhost, cur->name, cur->chans);
if ((cur->name[0] != '_') && (cur->name[0] != '\0')) {
if (strlen(cur->label))
snprintf(tmp, sizeof(tmp), "%s - %s", cur->name, cur->label);
else
snprintf(tmp, sizeof(tmp), "%s", cur->name);
} else
snprintf(tmp, sizeof(tmp), "%s", cur->label);
cur->next = extens;
cur->obj = gui_add_object(cur->name, tmp, cur->icon, cur->ident, cur, size, strlen(cur->chans) ? 1 : 0, TYPE_EXTEN);
if ((x > 0) && (y > 0))
gui_object_move(cur->obj, x, y);
extens = cur;
#if 0
printf("Added extension %s with %s and '%s'\n", exten, icon, label);
#endif
}
}
char *get_old_ident(void *pvt, char *old_ident, int old_ident_size)
{
struct ast_exten *exten = pvt;
snprintf(old_ident, old_ident_size, "[%s]exten[%s]", curhost, exten->name);
return old_ident;
}
static char *exten_file(void)
{
static char fn[256];
snprintf(fn, sizeof(fn), "%s" G_DIR_SEPARATOR_S ".gastman", gui_get_home_dir());
#ifndef _WIN32
mkdir(fn, 0777);
#else
_mkdir(fn);
#endif
if (gui_get_home_dir() && strlen(curhost)) {
snprintf(fn, sizeof(fn), "%s" G_DIR_SEPARATOR_S ".gastman" G_DIR_SEPARATOR_S "%s.extens", gui_get_home_dir(), curhost);
return fn;
}
return NULL;
}
static char *history_file(void)
{
static char fn[256];
snprintf(fn, sizeof(fn), "%s" G_DIR_SEPARATOR_S ".gastman", gui_get_home_dir());
#ifndef _WIN32
mkdir(fn, 0777);
#else
_mkdir(fn);
#endif
if (gui_get_home_dir() && strlen(curhost)) {
snprintf(fn, sizeof(fn), "%s" G_DIR_SEPARATOR_S ".gastman" G_DIR_SEPARATOR_S "%s.history", gui_get_home_dir(), curhost);
return fn;
}
return NULL;
}
static int loaded =0;
static void save_extens(void)
{
char *fn = exten_file();
struct ast_exten *cur;
FILE *f;
if (!fn)
return;
if (!loaded)
return;
if ((f = fopen(fn, "w"))) {
cur = extens;
while(cur) {
int x=0,y=0;
if (!gui_object_location(cur->obj, &x, &y))
fprintf(f, "%s:%s:%s:%i:%i:%s\n", cur->extens, cur->chans, cur->icon, x, y, cur->label);
else
fprintf(f, "%s:%s:%s:%i:%i:%s\n", cur->extens, cur->chans, cur->icon, 0, 0, cur->label);
cur = cur->next;
}
fclose(f);
}
}
static void save_history(void)
{
char *fn = history_file();
int x;
FILE *f;
if (!fn)
return;
if (!loaded)
return;
if ((f = fopen(fn, "w"))) {
for (x=0;x<maxhist;x++) {
if (history[x])
fprintf(f, "%s\n", history[x]);
}
fclose(f);
}
}
void gastman_add_exten(void)
{
char *exten = NULL, *chans = NULL, *icon = NULL, *label = NULL;
struct ast_exten *cur;
if (!gui_exten(&exten, &chans, &icon, &label, "Add Extension")) {
if (strlen(exten)) {
cur = extens;
while(cur) {
if (!strcasecmp(cur->name, exten))
break;
cur = cur->next;
}
if (cur) {
gui_show_message("In Use", "Sorry, that extension already exists!\n");
} else {
/* alloc_exten(exten, chans, icon, label); */
alloc_exten(exten, chans, icon, label, 1, -1, -1);
save_extens();
check_extens();
update_channels();
}
} else {
/* Blank extension (i.e. channel indicator) */
alloc_exten(exten, chans, icon, label, 1, -1, -1);
save_extens();
check_extens();
update_channels();
}
}
}
static void load_extens(void)
{
char *fn = exten_file();
char *exten, *chans = NULL, *x, *y;
char *icon, *label;
char buf[512];
char *tmp;
FILE *f;
loaded = 1;
if ((f = fopen(fn, "r"))) {
while(!feof(f)) {
fgets(buf, sizeof(buf), f);
if (!feof(f)) {
buf[strlen(buf) - 1] = '\0';
tmp = buf;
icon = label = NULL;
exten = strsep(&tmp, ":");
if (exten)
chans = strsep(&tmp, ":");
if (chans)
icon = strsep(&tmp, ":");
if (icon)
x = strsep(&tmp, ":");
if (x)
y = strsep(&tmp, ":");
if (y)
label = strsep(&tmp, ":");
else {
/* Backwards compatibility with old format */
label = x;
x = "0";
y = "0";
}
if (exten && icon && label)
alloc_exten(exten, chans, icon, label, 1, atoi(x), atoi(y));
}
}
fclose(f);
}
}
static void load_history(void)
{
char *fn = history_file();
char buf[512];
FILE *f;
loaded = 1;
maxhist = curhistpos = 0;
if ((f = fopen(fn, "r"))) {
while(!feof(f)) {
fgets(buf, sizeof(buf), f);
if (!feof(f)) {
buf[strlen(buf) - 1] = '\0';
if (curhistpos > MAX_HIST - 1)
shrink_hist();
history[curhistpos] = strdup(buf);
curhistpos++;
maxhist++;
}
}
fclose(f);
}
}
void gastman_quit(void)
{
save_extens();
save_history();
gui_exit();
}
static int event_link(struct mansession *s, struct message *m)
{
struct ast_chan *chan1, *chan2;
chan1 = find_chan(get_header(m, "Channel1"));
chan2 = find_chan(get_header(m, "Channel2"));
if (chan1 && chan2) {
strncpy(chan1->link, chan2->name, sizeof(chan1->link) - 1);
strncpy(chan2->link, chan1->name, sizeof(chan2->link) - 1);
gui_link(chan1->obj, chan2->obj);
}
update_channel(chan1);
update_channel(chan2);
return 0;
}
static int event_queueparams(struct mansession *s, struct message *m)
{
char *queue = get_header(m, "Queue");
struct ast_queuename *q;
int max = atoi(get_header(m, "Max"));
int calls = atoi(get_header(m, "Calls"));
printf("Queue %s has %d of %d members\n", queue, calls, max);
q = find_queuename(queue);
if (q) {
q->current = 0 /* calls */;
q->max = max;
gui_queue_set_queueinfo(q->obj, q->current, q->max);
}
return 0;
}
static int event_queueentry(struct mansession *s, struct message *m)
{
struct ast_queue *q;
char *queue = get_header(m, "Queue");
char *channel = get_header(m, "Channel");
char *callerid = get_header(m, "CallerID");
int position = atoi(get_header(m, "Position"));
int waittime = atoi(get_header(m, "Wait"));
q = find_queue(channel, queue);
printf("Channel %s on queue %s has position %d and has been waiting %d seconds\n",
channel, queue, position, waittime);
if (q) {
time(&q->start);
q->start -= waittime;
gui_queue_set_callinfo(q->obj, callerid, position, waittime);
}
return 0;
}
static int event_join(struct mansession *s, struct message *m)
{
struct ast_queue *q;
char *queue = get_header(m, "Queue");
char *channel = get_header(m, "Channel");
char *callerid = get_header(m, "CallerID");
int position = atoi(get_header(m, "Position"));
q = find_queue(channel, queue);
printf("Channel %s on queue %s has position %d.\n",
channel, queue, position);
time(&q->start);
gui_queue_set_callinfo(q->obj, callerid, position, 0);
return 0;
}
static int event_leave(struct mansession *s, struct message *m)
{
char *name = get_header(m, "Channel");
del_queue(name);
return 0;
}
static int event_unlink(struct mansession *s, struct message *m)
{
struct ast_chan *chan1, *chan2;
chan1 = find_chan(get_header(m, "Channel1"));
chan2 = find_chan(get_header(m, "Channel2"));
if (chan1 && chan2) {
strcpy(chan1->link, "");
strcpy(chan2->link, "");
gui_unlink(chan1->obj, chan2->obj);
}
return 0;
}
static struct event {
char *event;
int (*func)(struct mansession *s, struct message *m);
} events[] = {
{ "Newstate", event_newstate },
{ "Newchannel", event_newchannel },
{ "Newexten", event_newexten },
{ "Hangup", event_hangup },
{ "Rename", event_rename },
{ "Status", event_status },
{ "Link", event_link },
{ "Unlink", event_unlink },
{ "Newcallerid", event_newcallerid },
{ "QueueParams", event_queueparams },
{ "QueueEntry", event_queueentry },
{ "QueueMember", event_ignore },
{ "Join", event_join },
{ "Leave", event_leave },
};
static int process_message(struct mansession *s, struct message *m)
{
int x;
char event[80];
strncpy(event, get_header(m, "Event"), sizeof(event));
if (!strlen(event)) {
fprintf(stderr, "Missing event in request\n");
return 0;
}
for (x=0;x<sizeof(events) / sizeof(events[0]);x++) {
if (!strcasecmp(event, events[x].event)) {
if (events[x].func(s, m))
return -1;
break;
}
}
if (x >= sizeof(events) / sizeof(events[0]))
fprintf(stderr, "Ignoring unknown event '%s'\n", event);
#if 0
for (x=0;x<m->hdrcount;x++) {
printf("Header: %s\n", m->headers[x]);
}
#endif
return 0;
}
static int has_input(struct mansession *s)
{
int x;
for (x=1;x<s->inlen;x++)
if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r'))
return 1;
return 0;
}
static int get_input(struct mansession *s, char *output)
{
/* output must have at least sizeof(s->inbuf) space */
int res;
int x;
struct timeval tv = {0, 0};
fd_set fds;
for (x=1;x<s->inlen;x++) {
if ((s->inbuf[x] == '\n')) {
/* Copy output data up to and including \r\n */
memcpy(output, s->inbuf, x + 1);
/* Add trailing \0 */
output[x+1] = '\0';
/* Move remaining data back to the front */
memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x);
s->inlen -= (x + 1);
return 1;
}
}
if (s->inlen >= sizeof(s->inbuf) - 1) {
fprintf(stderr, "Dumping long line with no return from %s: %s\n", inet_ntoa(s->sin.sin_addr), s->inbuf);
s->inlen = 0;
}
FD_ZERO(&fds);
FD_SET(s->fd, &fds);
res = select(s->fd + 1, &fds, NULL, NULL, &tv);
if (res < 0) {
fprintf(stderr, "Select returned error: %s\n", strerror(errno));
} else if (res > 0) {
#ifndef _WIN32
res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
#else
res = recv(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen, 0);
#endif
if (res < 1)
return -1;
s->inlen += res;
s->inbuf[s->inlen] = '\0';
} else {
return 2;
}
return 0;
}
static struct message *mout;
static void dump_message(struct message *m)
{
int x;
printf("< Received:\n");
for (x=0;x<m->hdrcount;x++) {
printf("< %s\n", m->headers[x]);
}
printf("\n");
}
static int input_check(struct mansession *s)
{
static struct message m;
int res;
char *sp;
for(;;) {
res = get_input(s, m.headers[m.hdrcount]);
if (res == 1) {
#if 0
fprintf(stderr, "Got header: %s", m.headers[m.hdrcount]);
fgetc(stdin);
#endif
if (!m.gettingdata) {
/* Strip trailing \r\n */
if (strlen(m.headers[m.hdrcount]) < 2)
continue;
m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0';
if (!strlen(m.headers[m.hdrcount])) {
if (debug)
dump_message(&m);
if (mout && strlen(get_header(&m, "Response"))) {
memcpy(mout, &m, sizeof(m));
mout = NULL;
memset(&m, 0, sizeof(&m));
return 0;
}
if (process_message(s, &m))
break;
memset(&m, 0, sizeof(&m));
} else if (m.hdrcount < MAX_HEADERS - 1) {
if (!strncasecmp(m.headers[m.hdrcount], "Response: Follows", strlen("Response: Follows"))) {
m.gettingdata = 1;
}
m.hdrcount++;
}
} else {
/* Get raw data from command */
if ((sp = strstr(m.headers[m.hdrcount], "--END COMMAND--"))) {
/* End of getting data */
*sp = '\0';
m.gettingdata = 0;
}
if (m.hdrcount < MAX_HEADERS - 1)
m.hdrcount++;
}
} else if (res < 0) {
return -1;
} else if (res == 2)
return 0;
}
return -1;
}
static struct message *wait_for_response(int timeout)
{
static struct message m;
mout = &m;
while(mout && timeout) {
gui_run_a_little(&timeout);
}
mout = NULL;
return &m;
}
static void dump_out_message(char *action, char *tmp)
{
char *s;
printf("> Transmitted:\n");
printf("> Action: %s\n", action);
while(*tmp) {
s = tmp;
while(*s && (*s != '\r')) s++;
if (!*s)
break;
*s = '\0';
printf("> %s\n", tmp);
s+=2;
tmp = s;
}
printf("\n");
}
static int manager_action(char *action, char *fmt, ...)
{
struct mansession *s;
char tmp[4096];
va_list ap;
s = &session;
fdprintf(s->fd, "Action: %s\r\n", action);
va_start(ap, fmt);
vsnprintf(tmp, sizeof(tmp), fmt, ap);
va_end(ap);
#ifndef _WIN32
write(s->fd, tmp, strlen(tmp));
#else
send(s->fd, tmp, strlen(tmp), 0);
#endif
fdprintf(s->fd, "\r\n");
if (debug)
dump_out_message(action, tmp);
return 0;
}
static void try_status()
{
struct message *m;
manager_action("Status", "");
m = wait_for_response(10000);
if (!m) {
gui_show_message("Status Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Success")) {
gui_show_message("Status Failed", get_header(m, "Message"));
}
}
static void try_queuestatus()
{
struct message *m;
manager_action("QueueStatus", "");
m = wait_for_response(10000);
if (!m) {
gui_show_message("Queue Status Failed", "Timeout waiting for response");
}
}
static char *term_strip(char *dest, char *src, int buflen) {
int destoffset=0,srcoffset=0;
while (destoffset < buflen) {
switch (src[srcoffset]) {
case '\x1b':
while ((src[srcoffset] != 'm') && (src[srcoffset] != '\0'))
srcoffset++;
if (src[srcoffset] == 'm')
srcoffset++;
break;
default:
dest[destoffset++] = src[srcoffset++];
}
if (src[srcoffset] == '\0') {
dest[destoffset] = '\0';
break;
}
}
return dest;
}
static char *__gastman_run_command(const char *cmd)
{
static char buf[8192], buf2[8192];
int yah = 0;
int x;
struct message *m;
manager_action("Command", "Command: %s\r\n", cmd);
m = wait_for_response(100000);
if (!m) {
gui_show_message("Command Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Follows")) {
gui_show_message("Status Failed", get_header(m, "Message"));
} else {
memset(buf, 0, sizeof(buf));
for (x=0;x<m->hdrcount;x++) {
if (!strncasecmp(m->headers[x], "Response:", strlen("Response:")))
yah = 1;
else if (yah) {
strncat(buf, m->headers[x], sizeof(buf) - strlen(buf));
}
}
term_strip(buf2, buf, sizeof(buf2));
return buf2;
}
return NULL;
}
void gastman_run_command(const char *cmd)
{
char *buf;
if (cmd && strlen(cmd)) {
hist_append(cmd);
}
if (!strcasecmp(cmd, "quit") || !strcasecmp(cmd, "exit")) {
gui_status("Use File->Quit instead.");
return;
}
buf = __gastman_run_command(cmd);
if (buf)
gui_cli_result(buf);
}
void gastman_right_click(void *obj)
{
struct ast_chan *chan = obj;
if (chan->magic == CHAN_MAGIC) {
gui_show_chan_menu();
} else if (chan->magic == EXTEN_MAGIC) {
gui_show_exten_menu();
} else {
printf("Magic is %x\n", chan->magic);
}
}
int gastman_pre_drag_drop(void *src, void *dst)
{
struct ast_chan *chansrc = src;
struct ast_exten *extendst = dst;
struct ast_chan *chandst = dst;
int res = 0;
if ((chansrc->magic == CHAN_MAGIC) && (chandst->magic == EXTEN_MAGIC) &&
(extendst->extens[0] != '_')) {
res = 1;
} else if ((chansrc->magic == CHAN_MAGIC) && (chandst->magic == TRASH_MAGIC)) {
res = 1;
} else if ((chansrc->magic == EXTEN_MAGIC) && (chandst->magic == TRASH_MAGIC)) {
if (gui_confirm("Delete Confirmation", "Are you sure want to delete this extension?", 0, "confirmdelete"))
res = 1;
else
res = -1;
}
return res;
}
static void gastman_really_del_exten(void *data)
{
struct ast_exten *prev, *orig, *cur;
orig = data;
prev = NULL;
cur = extens;
prev = NULL;
while(cur) {
if (cur == orig) {
/* Unlink */
if (prev)
prev->next = cur->next;
else
extens = cur->next;
gui_del_object(cur->obj);
free(cur);
break;
}
prev = cur;
cur = cur->next;
}
}
void gastman_del_exten(void *data)
{
if (gui_confirm("Delete Confirmation", "Are you sure want to delete this extension?", 0, "confirmdelete"))
gastman_really_del_exten(data);
}
void gastman_drag_drop(void *src, void *dst)
{
struct ast_chan *chansrc = src;
struct ast_chan *chandst = dst;
struct ast_exten *extendst = dst;
struct ast_exten *extensrc = src;
char dest[256];
char source[256];
char tmp[256];
char xchan[256] = "";
char *context, *s;
struct message *m;
#if 0
printf("Drag %s onto %s\n", chansrc->name, chandst->name);
#endif
if ((chansrc->magic == CHAN_MAGIC) && (chandst->magic == EXTEN_MAGIC)) {
if (extendst->extens[0] == '_') {
gui_show_message("Redirect Failed", "That is not a valid extension to transfer to\n");
return;
}
if (strlen(chansrc->link)) {
snprintf(tmp, sizeof(tmp), "Do you want to transfer the person they're talking to (%s), too?", chansrc->link);
if (gui_yesno("Confirm additional transfer", tmp, 1))
snprintf(xchan, sizeof(xchan), "ExtraChannel: %s\r\n", chansrc->link);
}
strncpy(dest, extendst->name, sizeof(dest));
s = strchr(dest, ',');
if (s) *s = '\0';
/* Move src to destination */
if ((context = strchr(dest, '@'))) {
*context = '\0';
context++;
manager_action("Redirect", "Channel: %s\r\n%sContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chansrc->name,xchan,context,dest);
} else {
manager_action("Redirect", "Channel: %s\r\n%sExten: %s\r\nPriority: 1\r\n", chansrc->name, xchan, dest);
}
m = wait_for_response(10000);
if (!m) {
gui_show_message("Redirect Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Success")) {
gui_show_message("Redirect Failed", get_header(m, "Message"));
}
} else if ((chansrc->magic == CHAN_MAGIC) && (chandst->magic == TRASH_MAGIC)) {
/* Hangup */
gastman_hangup(chansrc);
} else if ((chansrc->magic = EXTEN_MAGIC) && (chandst->magic == TRASH_MAGIC)) {
gastman_really_del_exten(extensrc);
save_extens();
} else if ((chansrc->magic == EXTEN_MAGIC) && (chandst->magic == EXTEN_MAGIC)) {
if (extendst->extens[0] == '_') {
gui_show_message("Originate Failed", "That is not a valid extension to originate to\n");
return;
}
/* Call Destination from source */
strncpy(dest, extendst->name, sizeof(dest));
s = strchr(dest, ',');
if (s) *s = '\0';
strncpy(source, extensrc->chans, sizeof(source));
s = strchr(source, ',');
if (s) *s = '\0';
if (strlen(source)) {
if ((context = strchr(dest, '@'))) {
*context = '\0';
context++;
manager_action("Originate", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n",
source,context,dest);
} else {
manager_action("Originate", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n", source, dest);
}
m = wait_for_response(10000);
if (!m) {
gui_show_message("Originate Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Success")) {
gui_show_message("Originate Failed", get_header(m, "Message"));
}
} else {
snprintf(source, sizeof(source), "There is no channel associated with extension %s", extensrc->name);
gui_show_message("No channel", source);
}
}
}
void gastman_hangup(void *data)
{
struct ast_chan *chan = data;
struct message *m;
if (chan) {
manager_action("Hangup", "Channel: %s\r\n", chan->name);
m = wait_for_response(10000);
if (!m) {
gui_show_message("Hangup Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Success")) {
gui_show_message("Hangup Failed", get_header(m, "Message"));
}
}
}
void gastman_double_click(void *data)
{
struct ast_exten *cur = data;
char *exten, *chans, *icon, *label;
int x=0, y=0;
if (cur->magic == EXTEN_MAGIC) {
exten = cur->extens;
chans = cur->chans;
icon = cur->icon;
label = cur->label;
if (!gui_exten(&exten, &chans, &icon, &label, "Update Extension")) {
/* Delete old and add back */
if (!gui_object_location(cur->obj,&x,&y)) {
gastman_really_del_exten(cur);
alloc_exten(exten, chans, icon, label, 1, x, y);
} else {
gastman_really_del_exten(cur);
alloc_exten(exten, chans, icon, label, 1, -1, -1);
}
check_extens();
update_channels();
save_extens();
}
}
}
void gastman_redirect(void *data)
{
struct ast_chan *chan = data;
char dest[256];
struct message *m;
char channame[256];
char xchan[256] = "";
char tmp[80];
char *context;
if (chan) {
strncpy(channame, chan->name, sizeof(channame) - 1);
snprintf(tmp, sizeof(tmp), "Enter new extension for %s", channame);
if (gui_get_user_input("Redirect", tmp, dest, sizeof(dest)))
return;
if (strlen(chan->link)) {
snprintf(tmp, sizeof(tmp), "Do you want to transfer the person they're talking to (%s), too?", chan->link);
if (gui_yesno("Confirm additional transfer", tmp, 1))
snprintf(xchan, sizeof(xchan), "ExtraChannel: %s\r\n", chan->link);
}
if ((context = strchr(dest, '@'))) {
*context = '\0';
context++;
manager_action("Redirect", "Channel: %s\r\n%sContext: %s\r\nExten: %s\r\nPriority: 1\r\n", chan->name,xchan, context,dest);
} else {
manager_action("Redirect", "Channel: %s\r\n%sExten: %s\r\nPriority: 1\r\n", chan->name, xchan, dest);
}
m = wait_for_response(10000);
if (!m) {
gui_show_message("Redirect Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Success")) {
gui_show_message("Redirect Failed", get_header(m, "Message"));
}
}
}
void gastman_originate_exten(void *data)
{
struct ast_exten *exten = data;
char dest[256];
char channame[256];
struct message *m;
char tmp[80];
char *s;
char *context;
if (exten) {
if (!strlen(exten->chans)) {
snprintf(tmp, sizeof(tmp), "Can't originate since %s has no associated channels", exten->name);
gui_show_message("Invalid origination", tmp);
return;
}
strncpy(channame, exten->chans, sizeof(channame) - 1);
s = strchr(channame, ',');
if (s)
*s = '\0';
snprintf(tmp, sizeof(tmp), "Enter extension for %s", channame);
if (gui_get_user_input("Originate", tmp, dest, sizeof(dest)))
return;
if ((context = strchr(dest, '@'))) {
*context = '\0';
context++;
manager_action("Originate", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n",
channame,context,dest);
} else {
manager_action("Originate", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n",
channame,dest);
}
m = wait_for_response(10000);
if (!m) {
gui_show_message("Originate Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Success")) {
gui_show_message("Originate Failed", get_header(m, "Message"));
}
}
}
void gastman_invite_exten(void *data)
{
struct ast_exten *exten = data;
char dest[256];
char channame[256];
char ext[256];
struct message *m;
char tmp[80];
char *s;
char *context;
if (exten) {
if (exten->extens[0] == '_') {
snprintf(tmp, sizeof(tmp), "Can't originate since %s is a pattern match", exten->name);
gui_show_message("Invalid origination", tmp);
return;
}
strncpy(dest, exten->extens, sizeof(dest) - 1);
s = strchr(dest, ',');
if (s)
*s = '\0';
snprintf(tmp, sizeof(tmp), "Enter extension to invite to %s", dest);
if (gui_get_user_input("Invite", tmp, ext, sizeof(ext)))
return;
snprintf(channame, sizeof(channame), "Local/%s", ext);
if ((context = strchr(dest, '@'))) {
*context = '\0';
context++;
manager_action("Originate", "Channel: %s\r\nContext: %s\r\nExten: %s\r\nPriority: 1\r\n",
channame,context,dest);
} else {
manager_action("Originate", "Channel: %s\r\nExten: %s\r\nPriority: 1\r\n",
channame,dest);
}
m = wait_for_response(10000);
if (!m) {
gui_show_message("Invite Failed", "Timeout waiting for response");
} else if (strcasecmp(get_header(m, "Response"), "Success")) {
gui_show_message("Invite Failed", get_header(m, "Message"));
}
}
}
static int manage_calls(char *host)
{
/* If there's one thing you learn from this code, it is this...
Never, ever fly Air France. Their customer service is absolutely
the worst. I've never heard the words "That's not my problem" as
many times as I have from their staff -- It should, without doubt
be their corporate motto if it isn't already. Don't bother giving
them business because you're just a pain in their side and they
will be sure to let you know the first time you speak to them.
If you ever want to make me happy just tell me that you, too, will
never fly Air France again either (in spite of their excellent
cuisine). */
char tmp[256];
gui_show_box(host);
snprintf(tmp, sizeof(tmp), "[%s]trash", curhost);
gui_add_object("Trash", "Trash", "wastebasket", tmp, &wastebasket, 1, 0, TYPE_TRASH);
load_extens();
load_history();
gui_show_doing("Getting Status", "Retrieving system status...");
try_status();
try_queuestatus();
gui_hide_doing();
gui_run();
return 0;
}
int gastman_get_fd(void)
{
return session.fd;
}
int gastman_input_ready(void)
{
do {
if (input_check(&session)) {
#ifndef _WIN32
close(session.fd);
#else
closesocket(session.fd);
#endif
gui_show_message("Disconnected", "Disconnected from remote host");
save_extens();
gui_exit();
}
} while(has_input(&session));
return 0;
}
static int login(char *hostname)
{
char *user;
char *pass;
struct message *m;
char tmp[55];
struct hostent *hp;
int res = -1;
session.fd = socket(AF_INET, SOCK_STREAM, 0);
if (session.fd < 0) {
snprintf(tmp, sizeof(tmp), "socket() failed: %s\n", strerror(errno));
gui_show_message("Socket failed", tmp);
return -1;
}
if (gui_login(&user, &pass, hostname))
return -1;
snprintf(tmp, sizeof(tmp), "Looking up %s\n", hostname);
gui_show_doing("Connecting....", tmp);
strncpy(curhost, hostname, sizeof(curhost) - 1);
hp = gethostbyname(hostname);
if (!hp) {
snprintf(tmp, sizeof(tmp), "No such address: %s\n", hostname);
gui_show_message("Host lookup failed", tmp);
return -1;
}
gui_hide_doing();
snprintf(tmp, sizeof(tmp), "Connecting to %s", hostname);
gui_show_doing("Connecting...", tmp);
session.sin.sin_family = AF_INET;
session.sin.sin_port = htons(DEFAULT_MANAGER_PORT);
memcpy(&session.sin.sin_addr, hp->h_addr, sizeof(session.sin.sin_addr));
#ifndef _WIN32
if (connect(session.fd, (struct sockaddr *)&session.sin, sizeof(session.sin))) {
snprintf(tmp, sizeof(tmp), "%s failed: %s\n", hostname, strerror(errno));
#else
if (connect(session.fd, (struct sockaddr *)&session.sin, sizeof(session.sin)) == SOCKET_ERROR) {
snprintf(tmp, sizeof(tmp), "%s failed: %d\n", hostname, WSAGetLastError());
#endif
gui_show_message("Connect Failed", tmp);
return -1;
}
gui_watch_fd(session.fd);
gui_hide_doing();
snprintf(tmp, sizeof(tmp), "Logging in %s '...", user);
gui_show_doing("Logging in", tmp);
/* Check to see if remote host supports MD5 Authentication */
manager_action("Challenge", "AuthType: MD5\r\n");
m = wait_for_response(10000);
if (m && !strcasecmp(get_header(m, "Response"), "Success")) {
char *challenge = get_header(m, "Challenge");
int x;
int len = 0;
char md5key[256] = "";
struct MD5Context md5;
unsigned char digest[16];
MD5Init(&md5);
MD5Update(&md5, challenge, strlen(challenge));
MD5Update(&md5, pass, strlen(pass));
MD5Final(digest, &md5);
for (x=0; x<16; x++)
len += sprintf(md5key + len, "%2.2x", digest[x]);
manager_action("Login",
"AuthType: MD5\r\n"
"Username: %s\r\n"
"Key: %s\r\n",
user, md5key);
m = wait_for_response(10000);
gui_hide_doing();
if (m) {
if (!strcasecmp(get_header(m, "Response"), "Success")) {
res = 0;
} else {
gui_show_message("Login Failed", get_header(m, "Message"));
}
}
} else {
manager_action("Login",
"Username: %s\r\n"
"Secret: %s\r\n",
user, pass);
m = wait_for_response(10000);
gui_hide_doing();
if (m) {
if (!strcasecmp(get_header(m, "Response"), "Success")) {
res = 0;
} else {
gui_show_message("Login Failed", get_header(m, "Message"));
}
}
}
return res;
}
int main(int argc, char *argv[])
{
char host[256] = "";
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
int err;
#endif
#ifdef _WIN32
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
fprintf(stderr, "WSAStartup: Could not find usable WinsSock DLL\n");
return 1;
}
#endif
gui_init(&argc, &argv);
argv++;
argc--;
if (argc && !strcmp(*argv, "-d")) {
debug = 1;
argc--;
argv++;
}
if (argc)
strncpy(host, *argv, sizeof(host) - 1);
if (strlen(host) ||
(!gui_get_hostname(host, sizeof(host) - 1) &&
strlen(host))) {
if (!login(host)) {
manage_calls(host);
}
}
#ifdef _WIN32
WSACleanup( );
#endif
return 0;
}
char *gastman_prevhist(void)
{
if (curhistpos > 0) {
curhistpos--;
return history[curhistpos];
}
return NULL;
}
char *gastman_nexthist(void)
{
if (curhistpos<maxhist) {
curhistpos++;
return history[curhistpos];
}
return NULL;
}
char *gastman_complete(const char *orig, int *pos)
{
static char buf[4096];
char cmd[4096];
char tmp[4096];
char sch[1024];
const char *ptr;
int len;
int count;
int excl;
char *ret;
char *w, *n;
strncpy(buf, orig, sizeof(buf) - 1);
#if 0
printf("Completing %s at position %d\n", orig, *pos);
#endif
ptr = orig + *pos;
if (ptr) {
while (ptr > orig) {
if (isspace(*ptr)) {
ptr++;
break;
}
ptr--;
}
}
len = ptr - orig;
snprintf(cmd, sizeof(cmd), "_COMMAND NUMMATCHES \"%s\" \"%s\"", orig, ptr);
#if 0
printf("Command: '%s'\n", cmd);
#endif
ret = __gastman_run_command(cmd);
if (ret) {
if ((sscanf(ret, "%d", &count) == 1)) {
/* Check for a count */
if (count) {
snprintf(cmd, sizeof(cmd), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", orig, ptr);
#if 0
printf("Command: '%s'\n", cmd);
#endif
ret = __gastman_run_command(cmd);
#if 0
printf("Ret is '%s'\n", ret);
#endif
w = ret;
while(*w && (*w > 32)) w++;
if (*w) {
*w = '\0';
w++;
}
excl = 1;
if (strlen(ret) && strcmp(ret, ptr)) {
while(*w) {
n = w;
while(*n && (*n > 32)) n++;
if (*n) {
*n = '\0';
n++;
if (strcmp(w, ret)) {
excl = 0;
break;
}
}
w = n;
}
} else
excl = 0;
snprintf(buf + len, sizeof(buf) - len, "%s%s", ret, excl ? " " : "");
*pos = len + strlen(ret) + excl;
if (!strlen(ret) || !strcmp(ret, ptr)) {
strcpy(tmp, "Possibilities: ");
while(*w) {
n = w;
while(*n && (*n > 32)) n++;
if (*n) {
*n = '\0';
n++;
snprintf(sch, sizeof(sch), "%s ", w);
if (!strstr(tmp, sch))
strcat(tmp, sch);
}
w = n;
}
gui_status(tmp);
} else
gui_status("");
} else
gui_status("No matches");
}
}
return buf;
}
syntax highlighted by Code2HTML, v. 0.9.1