dockapps/wmisdn/wmisdn.cc
2018-01-08 16:08:44 -02:00

1609 lines
44 KiB
C++

/* wmisdn - an ISDN monitor applet for windowmaker/afterstep
* Copyright (c) 2000-2001 Tasho Statev Kaletha
* tasho.kaletha@gmx.de
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/* these defaults can be changed by command line options. */
#define WINDOWMAKER false
#define USESHAPE false
#define NAME "wmisdn"
#define CLASS "WMIsdn"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <syslog.h>
#include <asm/errno.h> /* for ENOTCONN */
#include <errno.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xproto.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include <linux/isdn.h>
#include <linux/isdnif.h>
#include <time.h>
#include "regions.h"
#include "optics/optics.h"
static Pixmap coverPixmap;
static Pixmap unknownPixmap;
static Pixmap dialingPixmap;
static Pixmap offPixmap;
static Pixmap disabledPixmap;
static Pixmap statusPixmaps[6];
static Pixmap incomingPixmap, outgoingPixmap, bundlingPixmap, bundledPixmap, slavePixmap;
static Pixmap ledsPixmap; /* a row of led symbols as shown by the var led_text below */
static Pixmap lampsPixmap; /* a row of lamp images - green off, green on, yellow off, yellow on, red off, red on */
static Pixmap infoSWPixmap; /* a row of arrows - left off, left on, right off, right on */
static Pixmap lampsSWPixmap; /* a row of arrows - up off, up on, down off, down on */
#include "xpm/unknown.xpm"
#include "xpm/disabled.xpm"
#include "xpm/off.xpm"
#include "xpm/offline.xpm"
#include "xpm/dialing.xpm"
#include "xpm/incoming.xpm"
#include "xpm/outgoing.xpm"
#include "xpm/bundling.xpm"
#include "xpm/bundled.xpm"
#include "xpm/slave.xpm"
#include "xpm/raw.xpm"
#include "xpm/modem.xpm"
#include "xpm/online.xpm"
#include "xpm/voice.xpm"
#include "xpm/fax.xpm"
#include "xpm/cover.xpm"
#include "xpm/leds.xpm"
#include "xpm/lamps.xpm"
#include "xpm/lamps_sw.xpm"
#include "xpm/info_sw.xpm"
/* Runtime pixmaps */
static Pixmap disp_info; /* double buffer for the info panel */
static Pixmap disp; /* for the main window */
static Pixmap dmsk; /* clip mask for the main window */
/* For command line arguments */
#define MAX_ARG_LEN 256
static bool wmaker = WINDOWMAKER;
static bool ushape = USESHAPE;
static char txtdpy[MAX_ARG_LEN] = "";
static char txtfont[MAX_ARG_LEN] = "";
static int dialmode = ISDN_NET_DM_AUTO;
static char devices[ISDN_MAX_CHANNELS][MAX_ARG_LEN];
static int selected_device=-1; /* selected device, points to an element of devices[] */
static char scriptpath[MAX_ARG_LEN] = "/etc/isdn";
static int scriptmode = 0;
static bool usescripts = false;
static int maxscriptmode = 0;
static char** scriptmodestrings = NULL;
static char *slave_pending = NULL;
/* atoms for deleting window */
static Atom _XA_GNUSTEP_WM_FUNC;
static Atom WM_DELETE_WINDOW;
/* global variables */
Display *dpy;
Window Win[3]; /* 0 - main win, 1 - icon win (for wmaker), 2 - info panel */
Window Root;
GC WinGC;
int activeWin;
XFontStruct *textFont=NULL;
static char led_text[] = "0123456789?/\\!@#$%^&*()_+-=\"~<>[]{}:. abcdefghijklmnopqrstuvwxyz";
static int rootUID, rootGID;
static bool infoPanelActive = false;
static bool lampsActive = false;
/* Der scriptmode wird als 2. Argument den Start-/Stopskripten uebergeben.
Aenderung mit mittlerer Maustaste auf InfoSw bei offenem Infopanel. */
#define ACTIVE 1 /* values are not only symbolc, but important for calculations! */
#define INACTIVE 0
#define ID_LAMP_GREEN 0
#define ID_LAMP_YELLOW 1
#define ID_LAMP_RED 2
#define ID_SWITCH_INFO 10
#define ID_SWITCH_LAMPS 11
#define ID_SWITCH_STATUS 19
#define ID_DEVICE 20
#define UPDATE_INTERVAL 20 /* how many 50 milisec intervalls to wait between updates */
#define STATUS_WARNING_SAT 5 /* how many times to display a warning upon failing to retrieve device stats */
#define INCOMING 0
#define OUTGOING 1
#define STAT_DISABLED 1000
#define STAT_OFF 1001
#define STAT_DIALING 1002
#define STAT_UNKNOWN 2001
#define STAT_UNINITIALIZED 2002
#define SCRIPT_UP "wmisdn-up"
#define SCRIPT_DOWN "wmisdn-down"
#define SCRIPT_MODES "wmisdn-scriptmodes"
typedef enum mpppModeType { none, master, slave };
struct isdnStatus
{
int usage;
int direction;
bool bundled;
char peerPhone[100];
mpppModeType mpppMode;
char mpppPartner[100];
} curStatus = { STAT_UNINITIALIZED, INCOMING, false, "", none, "" };
/* text i/o routines */
bool scanArgs(int argc, char *argv[]);
void printUsage( char *prog_name );
void printHeader();
void parseDeviceNames( char *name_list );
void readScriptModes();
/* init/done routines */
void initXWin(int argc, char *argv[]);
void freeXWin();
void createMainWin( Window *win );
void createInfoPanel( Window *win );
void loadPixmaps();
void freePixmaps();
void createRegions();
/* window routines */
void alignInfoPanel();
void getWindowPosition( Window win, int *x, int *y );
void getWindowDimension( Window win, int *w, int *h );
/* graphic routines */
unsigned long getColor(const char *colorname);
void createPixmap(char *data[], Pixmap *image, Pixmap *mask );
void loadLeds(char *data[], Pixmap *image, const char *leds_color, const char *back_color );
void drawText( char *text, Pixmap dst, int x, int y, const char *color=InfoTextColor );
void drawLamp( int index, int active );
void drawDevice( int active = INACTIVE );
unsigned long mixColor( const char *colorname1, int prop1, const char *colorname2, int prop2);
/* interaction routines */
bool timeToUpdate();
void update();
void fullRepaint();
void repaint( Window win, int x, int y, int w, int h );
void setStatusPixmap();
void updateInfoPanel();
void blankMainWin( int x=0, int y=0, int w=MainWinDim.w, int h=MainWinDim.h );
void pressLamp( int lamp, int button );
void pressStatusSw();
void activateLamps( bool active );
void drawSwitches();
/* region event handlers */
void mouseInLamp( int id );
void mouseOutLamp( int id );
void mouseClickLamp( int id, unsigned int button );
void mouseInInfoSw( int id );
void mouseOutInfoSw( int id );
void mouseClickInfoSw( int id, unsigned int button );
void mouseInLampsSw( int id );
void mouseOutLampsSw( int id );
void mouseClickLampsSw( int id, unsigned int button );
void mouseInDevice( int id );
void mouseOutDevice( int id );
void mouseClickDevice( int id, unsigned int button );
void mouseInStatusSw( int id );
void mouseOutStatusSw( int id );
void mouseClickStatusSw( int id, unsigned int button );
void selectNextDevice();
/* event handlers */
void exposeEvent( XExposeEvent *xev);
void pressEvent(XButtonEvent *xev);
void motionEvent( XMotionEvent *xev );
/* ISDN routines */
void getStatus( char *device, isdnStatus *stat );
void getLocalIP( int *a, int *b, int *c, int *d );
inline void getRemoteIP( int *a, int *b, int *c, int *d );
inline void translateIP( struct sockaddr *addr, int *a, int *b, int *c, int *d );
int isdn_ioctl( int func, void *arg, const char *errmsg, const char *filename="/dev/isdnctrl" );
void isdnInitDefaultDialmode();
int getIpppNum( char *name );
inline void set_slave_pending();
inline void clear_slave_pending();
inline bool is_slave_pending();
inline void manage_slave();
/* -------- Implementation ----------- */
int main(int argc, char *argv[])
{
rootUID = geteuid(); rootGID = getegid();
seteuid(getuid()); setegid(getgid());
printHeader();
if( !scanArgs(argc, argv) )
{
printUsage( argv[0] );
return 1;
}
readScriptModes();
initXWin(argc, argv);
loadPixmaps();
createRegions();
disp = XCreatePixmap(dpy, Root, MainWinDim.w, MainWinDim.h, DefaultDepth(dpy,DefaultScreen(dpy)));
disp_info = XCreatePixmap(dpy, Root, InfoWinDim.w, InfoWinDim.h, DefaultDepth(dpy,DefaultScreen(dpy)));
XGCValues gcv;
unsigned long gcm;
gcm = GCGraphicsExposures|GCBackground;
gcv.graphics_exposures = True;
gcv.background = getColor( WindowBackgroundColor );
if( strlen(txtfont) != 0 )
{
textFont = XLoadQueryFont( dpy, txtfont );
if( textFont != NULL )
{
gcm |= GCFont;
gcv.font = textFont->fid;
} else
syslog( LOG_NOTICE, "Couldn't load specified font" );
}
WinGC = XCreateGC(dpy, Root, gcm, &gcv);
blankMainWin();
drawDevice(INACTIVE);
activateLamps( lampsActive );
drawSwitches();
update();
if(!(wmaker || ushape))
XSetClipMask(dpy, WinGC, dmsk);
else
XShapeCombineMask(dpy, Win[activeWin], ShapeBounding, 0, 0, dmsk, ShapeSet);
XSetClipOrigin(dpy, WinGC, 0, 0);
XSetClipMask(dpy, WinGC, None);
XEvent event;
XSelectInput(dpy, Win[activeWin], PointerMotionMask | ButtonPress | ExposureMask);
XSelectInput(dpy, Win[2], ExposureMask );
XMapWindow(dpy, Win[0]);
bool finished=false;
while(!finished){
while(XPending(dpy)){
XNextEvent(dpy,&event);
switch(event.type){
case ButtonPress : pressEvent(&event.xbutton); break;
case MotionNotify : motionEvent(&event.xmotion); break;
case ClientMessage :
if((Atom)event.xclient.data.l[0]==WM_DELETE_WINDOW)
finished=true;
break;
case Expose : exposeEvent( &event.xexpose ); break;
}
}
if( timeToUpdate() )
{
update();
manage_slave();
}
usleep(50000);
}
if( textFont != NULL )
XFreeFont( dpy, textFont );
XFreeGC(dpy, WinGC);
freePixmaps();
/* Free runtime pixmaps */
XFreePixmap(dpy, disp_info);
XFreePixmap(dpy, disp);
XFreePixmap(dpy, dmsk);
/* Finish with X stuff */
freeXWin();
return 0;
}
void initXWin(int argc, char *argv[])
{
if( (dpy=XOpenDisplay(txtdpy)) == NULL )
{
fprintf(stderr,"cannot open display!\n");
exit(1);
}
_XA_GNUSTEP_WM_FUNC = XInternAtom(dpy, "_GNUSTEP_WM_FUNCTION", false);
WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
Root=DefaultRootWindow(dpy);
createMainWin(&Win[0]);
createMainWin(&Win[1]);
createInfoPanel( &Win[2] );
XWMHints hints;
XSizeHints shints;
hints.window_group = Win[0];
shints.min_width=64;
shints.min_height=64;
shints.max_width=64;
shints.max_height=64;
shints.x=0;
shints.y=0;
if(wmaker)
{
hints.initial_state = WithdrawnState;
hints.icon_window = Win[1];
hints.flags = WindowGroupHint | StateHint | IconWindowHint;
shints.flags = PMinSize | PMaxSize | PPosition;
activeWin=1;
}
else {
hints.initial_state = NormalState;
hints.flags = WindowGroupHint | StateHint;
shints.flags = PMinSize | PMaxSize;
activeWin=0;
}
XSetWMHints(dpy, Win[0], &hints);
XSetWMNormalHints(dpy, Win[0], &shints);
XSetCommand(dpy, Win[0], argv, argc);
XStoreName(dpy, Win[0], NAME);
XSetIconName(dpy, Win[0], NAME);
XSetWMProtocols(dpy, Win[activeWin], &WM_DELETE_WINDOW, 1);
}
void freeXWin()
{
XDestroyWindow(dpy, Win[0]);
XDestroyWindow(dpy, Win[1]);
XDestroyWindow(dpy, Win[2]);
XCloseDisplay(dpy);
}
void loadPixmaps()
{
createPixmap(cover_xpm, &coverPixmap, &dmsk );
createPixmap(dialing_xpm, &dialingPixmap, NULL );
createPixmap(unknown_xpm, &unknownPixmap, NULL );
createPixmap(disabled_xpm, &disabledPixmap, NULL );
createPixmap(off_xpm, &offPixmap, NULL );
createPixmap(incoming_xpm, &incomingPixmap, NULL );
createPixmap(outgoing_xpm, &outgoingPixmap, NULL );
createPixmap(bundling_xpm, &bundlingPixmap, NULL );
createPixmap(bundled_xpm, &bundledPixmap, NULL );
createPixmap(slave_xpm, &slavePixmap, NULL );
createPixmap(offline_xpm, &statusPixmaps[ISDN_USAGE_NONE], NULL );
createPixmap(raw_xpm, &statusPixmaps[ISDN_USAGE_RAW], NULL );
createPixmap(modem_xpm, &statusPixmaps[ISDN_USAGE_MODEM], NULL );
createPixmap(online_xpm, &statusPixmaps[ISDN_USAGE_NET], NULL );
createPixmap(voice_xpm, &statusPixmaps[ISDN_USAGE_VOICE], NULL );
createPixmap(fax_xpm, &statusPixmaps[ISDN_USAGE_FAX], NULL );
createPixmap(lamps_xpm, &lampsPixmap, NULL );
createPixmap(info_sw_xpm, &infoSWPixmap, NULL );
createPixmap(lamps_sw_xpm, &lampsSWPixmap, NULL );
loadLeds( leds_xpm, &ledsPixmap, InfoTextColor, WindowBackgroundColor );
}
void freePixmaps()
{
XFreePixmap(dpy, coverPixmap);
XFreePixmap(dpy, dialingPixmap);
XFreePixmap(dpy, unknownPixmap);
XFreePixmap(dpy, disabledPixmap);
XFreePixmap(dpy, offPixmap);
XFreePixmap(dpy, incomingPixmap);
XFreePixmap(dpy, outgoingPixmap);
XFreePixmap(dpy, bundlingPixmap);
XFreePixmap(dpy, bundledPixmap);
XFreePixmap(dpy, slavePixmap);
for( int i=ISDN_USAGE_NONE; i < ISDN_USAGE_FAX; i++ )
XFreePixmap( dpy, statusPixmaps[i] );
XFreePixmap(dpy, ledsPixmap);
XFreePixmap(dpy, lampsPixmap);
XFreePixmap(dpy, infoSWPixmap);
XFreePixmap(dpy, lampsSWPixmap);
}
void createMainWin( Window *win )
{
*win = XCreateSimpleWindow(dpy, Root, 10, 10, MainWinDim.w, MainWinDim.h,0,0,0);
XClassHint classHint;
classHint.res_name = NAME;
classHint.res_class = CLASS;
XSetClassHint(dpy, *win, &classHint);
}
void createInfoPanel( Window *win )
{
*win = XCreateSimpleWindow(dpy, Root, 10, 10, InfoWinDim.w, InfoWinDim.h,0,0,0);
XSizeHints shints;
shints.flags = PPosition;
XSetWMNormalHints( dpy, *win, &shints );
XClassHint classHint;
classHint.res_name = "Info";
classHint.res_class = CLASS;
XSetClassHint(dpy, *win, &classHint);
}
void createRegions()
{
region_init(dpy);
region_add( Win[activeWin], ID_LAMP_GREEN, LampsRect[ID_LAMP_GREEN].pos.x, LampsRect[ID_LAMP_GREEN].pos.y, LampsRect[ID_LAMP_GREEN].dim.w, LampsRect[ID_LAMP_GREEN].dim.h, mouseInLamp, mouseOutLamp, mouseClickLamp );
region_add( Win[activeWin], ID_LAMP_YELLOW, LampsRect[ID_LAMP_YELLOW].pos.x, LampsRect[ID_LAMP_YELLOW].pos.y, LampsRect[ID_LAMP_YELLOW].dim.w, LampsRect[ID_LAMP_YELLOW].dim.h, mouseInLamp, mouseOutLamp, mouseClickLamp );
region_add( Win[activeWin], ID_LAMP_RED, LampsRect[ID_LAMP_RED].pos.x, LampsRect[ID_LAMP_RED].pos.y, LampsRect[ID_LAMP_RED].dim.w, LampsRect[ID_LAMP_RED].dim.h, mouseInLamp, mouseOutLamp, mouseClickLamp );
region_add( Win[activeWin], ID_SWITCH_INFO, InfoSWRect.pos.x, InfoSWRect.pos.y, InfoSWRect.dim.w, InfoSWRect.dim.h, mouseInInfoSw, mouseOutInfoSw, mouseClickInfoSw );
region_add( Win[activeWin], ID_SWITCH_LAMPS, LampsSWRect.pos.x, LampsSWRect.pos.y, LampsSWRect.dim.w, LampsSWRect.dim.h, mouseInLampsSw, mouseOutLampsSw, mouseClickLampsSw );
region_add( Win[activeWin], ID_DEVICE, DeviceRect.pos.x, DeviceRect.pos.y, DeviceRect.dim.w, DeviceRect.dim.h, mouseInDevice, mouseOutDevice, mouseClickDevice );
region_add( Win[activeWin], ID_SWITCH_STATUS, StatusPixmapRect.pos.x, StatusPixmapRect.pos.y, StatusPixmapRect.dim.w, StatusPixmapRect.dim.h, mouseInStatusSw, mouseOutStatusSw, mouseClickStatusSw );
}
bool validIppp( char *name )
{
if( strlen(name) < 5 )
return false;
if( strncmp( name, "ippp", 4 ) != 0 )
return false;
for( char *p=name+4; *p != '\x0'; p++ )
if( !isdigit(*p) )
return false;
if( getIpppNum(name) >= ISDN_MAX_CHANNELS )
return false;
return true;
}
int getIpppNum( char *name )
{
return atoi( name + 4 );
}
void selectNextDevice()
{
selected_device++;
if( devices[selected_device][0] == 0 )
selected_device = 0;
drawDevice();
update();
}
void printUsage( char *prog_name )
{
fprintf( stderr, "usage:\n\n %s [options]\n\noptions:\n\n", prog_name );
fprintf( stderr, " -h | -help | --help display this help screen\n");
fprintf( stderr, " -w use WithdrawnState (for WindowMaker)\n" );
fprintf( stderr, " -s shaped window\n" );
fprintf( stderr, " -display display select target display (see X manual pages)\n" );
fprintf( stderr, " -font font select the font for displaying status information\n" );
fprintf( stderr, " -dialmode mode select dial mode for offline mode (auto or manual)\n" );
fprintf( stderr, " -device device select ippp devices to monitor\n" );
fprintf( stderr, " (a list of comma-separated device names is expected containing __no blanks__)\n" );
fprintf( stderr, " -lamps activate the line control switches upon startup\n" );
fprintf( stderr, " -usescripts use user scripts for dialing/hanging up instead of direct ioctl calls\n" );
fprintf( stderr, " -path path select directory with the up-/down-scripts\n\n" );
}
void printHeader()
{
fprintf( stderr, "wmisdn v1.8 (C) 1999-2001 Tasho Statev Kaletha (kaletha@informatik.uni-bonn.de).\n\n" );
}
void parseDeviceNames( char *name_list )
{
char *ptr1, *ptr2;
int i;
ptr1 = name_list;
for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
{
ptr2 = strchr(ptr1,',');
if( ptr2 == NULL )
ptr2 = &name_list[strlen(name_list)];
strncpy( devices[i], ptr1, ptr2-ptr1 );
devices[i][ptr2-ptr1] = 0;
devices[i+1][0] = 0;
if( !validIppp(devices[i]) )
fprintf( stderr, "Warning : \"%s\" doesn't seem to be a valid ippp device. wmisdn may not work properly\n", devices[i] );
if( ptr2[0] == 0 )
return;
ptr1 = ptr2+1;
}
}
bool scanArgs(int argc, char *argv[])
{
bool dialmode_set = false;
for(int i=1;i<argc;i++)
{
if(strcmp(argv[i],"-h")==0 || strcmp(argv[i],"-help")==0 || strcmp(argv[i],"--help")==0)
return false;
else if(strcmp(argv[i],"-w")==0)
wmaker=true;
else if(strcmp(argv[i],"-s")==0)
ushape=true;
else if(strcmp(argv[i],"-lamps")==0)
lampsActive=true;
else if(strcmp(argv[i],"-usescripts")==0)
usescripts=true;
else if(strcmp(argv[i],"-display")==0)
{
if(i<argc-1)
{
i++;
if( strlen(argv[i]) > MAX_ARG_LEN-1 )
{
fprintf( stderr, "Argument for -display option too long\n" );
return false;
}
sprintf(txtdpy,"%s",argv[i]);
}
continue;
}
else if(strcmp(argv[i],"-font")==0)
{
if(i<argc-1)
{
i++;
if( strlen(argv[i]) > MAX_ARG_LEN-1 )
{
fprintf( stderr, "Argument for -font option too long\n" );
return false;
}
sprintf(txtfont,"%s",argv[i]);
}
continue;
}
else if(strcmp(argv[i],"-dialmode")==0)
{
if(i<argc-1)
{
i++;
if( strcmp(argv[i], "auto")==0 )
dialmode = ISDN_NET_DM_AUTO;
else if( strcmp(argv[i], "manual")==0 )
dialmode = ISDN_NET_DM_MANUAL;
else {
fprintf( stderr, "Unknown dial mode \"%s\"\n", argv[i] );
return false;
}
dialmode_set = true;
}
}
else if(strcmp(argv[i],"-device")==0)
{
if(i<argc-1)
{
i++;
if( strlen(argv[i]) > MAX_ARG_LEN-1 )
{
fprintf( stderr, "Argument for -device option too long\n" );
return false;
}
parseDeviceNames( argv[i] );
selected_device = 0;
}
}
else if(strcmp(argv[i],"-path")==0)
{
if(i<argc-1)
{
i++;
if( strlen(argv[i]) > MAX_ARG_LEN-1 )
{
fprintf( stderr, "Argument for -path option too long\n" );
return false;
}
strcpy( scriptpath, argv[i] );
}
}
else {
fprintf( stderr, "Unknown option \"%s\"\n", argv[i] );
return false;
}
}
if( !dialmode_set )
isdnInitDefaultDialmode();
if( selected_device == -1 )
{
strcpy( devices[0], "ippp0" );
devices[1][0] = 0;
selected_device = 0;
}
return true;
}
/* Reads the string representations of the scriptmode parameter given to the up/down scripts
* and initializes the coresponding variables */
void readScriptModes()
{
char filename[1000];
char buf[1000];
sprintf( filename, "%s/%s", scriptpath, SCRIPT_MODES );
FILE *f = fopen( filename, "r" );
/* init one default string if reading fails */
if( f == NULL || (fgets(buf,sizeof(buf),f) == NULL) || !usescripts )
{
maxscriptmode = 0;
if( usescripts )
syslog( LOG_NOTICE, "Couldn't read script mode strings: %m" );
scriptmodestrings = (char **)malloc( sizeof(char*) );
scriptmodestrings[0] = (char *)malloc( sizeof("go online") );
strcpy(scriptmodestrings[0], "go online" );
if( f != NULL )
fclose(f);
return;
}
maxscriptmode = -1; /* the first iteration sets it to 0 - first array index */
/* read the strings and put them into the scriptmodestrings array */
do
{
maxscriptmode++;
scriptmodestrings = (char **)realloc( scriptmodestrings, (maxscriptmode+1)*sizeof(char*) );
scriptmodestrings[maxscriptmode] = (char *)malloc( strlen(buf)+1 );
while( strchr(buf,'\n') != NULL )
*strchr(buf,'\n') = '\0';
strcpy( scriptmodestrings[maxscriptmode], buf );
} while( fgets(buf,sizeof(buf),f) != NULL );
fclose(f);
}
void advanceScriptMode()
{
scriptmode++;
if(scriptmode > maxscriptmode)
scriptmode = 0;
update();
}
/* press event
* - if a lamp is pressed then the corresponding actions are taken.
* - outside a lamp the extended view is turned on or off
*/
void pressEvent(XButtonEvent *xev)
{
if( region_in( xev->window, xev->x, xev->y ) )
region_mouse_click( xev->window, xev->x, xev->y, xev->button );
}
/* pointer motion
* - draws a lamp in an active state if the pointer passes above it
*/
void motionEvent( XMotionEvent *xev )
{
region_mouse_motion( xev->window, xev->x, xev->y );
}
void exposeEvent( XExposeEvent *xev )
{
repaint( xev->window, xev->x, xev->y, xev->width, xev->height );
}
void alignInfoPanel()
{
/* get the position of the main win */
int win_x, win_y, screen_w, screen_h, panel_x, panel_y;
getWindowPosition( Win[activeWin], &win_x, &win_y );
getWindowDimension( Root, &screen_w, &screen_h );
/* find a suitable position for the info panel */
if( win_x - InfoWinDim.w > 0 )
panel_x = win_x - InfoWinDim.w;
else
panel_x = win_x + MainWinDim.w;
panel_y = win_y;
/* move the panel */
XMoveWindow( dpy, Win[2], panel_x, panel_y );
}
void mouseInLamp( int id )
{
drawLamp( id, ACTIVE );
for( int i=0; i < 3; i++ )
repaint( Win[activeWin], LampsRect[i].pos.x, LampsRect[i].pos.y, LampsRect[i].dim.w, LampsRect[i].dim.h );
}
void mouseOutLamp( int id )
{
drawLamp( id, INACTIVE );
for( int i=0; i < 3; i++ )
repaint( Win[activeWin], LampsRect[i].pos.x, LampsRect[i].pos.y, LampsRect[i].dim.w, LampsRect[i].dim.h );
}
void mouseClickLamp( int id, unsigned int button )
{
pressLamp( id, button );
update();
}
inline void drawInfoSwitch( int active )
{
int pixmap_index = (infoPanelActive ? 2:0) + active;
int offset_x = pixmap_index * InfoSWRect.dim.w;
XCopyArea( dpy, infoSWPixmap, disp, WinGC, offset_x, 0, InfoSWRect.dim.w, InfoSWRect.dim.h, InfoSWRect.pos.x, InfoSWRect.pos.y );
repaint( Win[activeWin], InfoSWRect.pos.x, InfoSWRect.pos.y, InfoSWRect.dim.w, InfoSWRect.dim.h );
}
void mouseInInfoSw( int id )
{
drawInfoSwitch(ACTIVE);
}
void mouseOutInfoSw( int id )
{
drawInfoSwitch(INACTIVE);
}
void mouseClickInfoSw( int id, unsigned int button )
{
if( !infoPanelActive )
{
alignInfoPanel();
XMapWindow( dpy, Win[2] );
} else
XUnmapWindow( dpy, Win[2] );
infoPanelActive = !infoPanelActive;
mouseInInfoSw( ID_SWITCH_INFO );
fullRepaint();
}
inline void drawLampsSwitch( int active )
{
int pixmap_index = (lampsActive ? 2:0) + active;
int offset_x = pixmap_index * LampsSWRect.dim.w;
XCopyArea( dpy, lampsSWPixmap, disp, WinGC, offset_x, 0, LampsSWRect.dim.w, LampsSWRect.dim.w, LampsSWRect.pos.x, LampsSWRect.pos.y );
repaint( Win[activeWin], LampsSWRect.pos.x, LampsSWRect.pos.y, LampsSWRect.dim.w, LampsSWRect.dim.h );
}
void mouseInLampsSw( int id )
{
drawLampsSwitch(ACTIVE);
}
void mouseOutLampsSw( int id )
{
drawLampsSwitch(INACTIVE);
}
void mouseClickLampsSw( int id, unsigned int button )
{
activateLamps( !lampsActive );
mouseInLampsSw( ID_SWITCH_LAMPS );
}
void activateLamps( bool active )
{
if( active )
{
drawLamp( 0, INACTIVE );
drawLamp( 1, INACTIVE );
drawLamp( 2, INACTIVE );
region_enable( Win[activeWin], ID_LAMP_GREEN );
region_enable( Win[activeWin], ID_LAMP_YELLOW );
region_enable( Win[activeWin], ID_LAMP_RED );
} else {
for( int i=0; i < 3; i++ )
blankMainWin( LampsRect[i].pos.x, LampsRect[i].pos.y, LampsRect[i].dim.w, LampsRect[i].dim.h );
region_disable( Win[activeWin], ID_LAMP_GREEN );
region_disable( Win[activeWin], ID_LAMP_YELLOW );
region_disable( Win[activeWin], ID_LAMP_RED );
}
lampsActive = active;
fullRepaint();
}
void drawSwitches()
{
drawInfoSwitch( INACTIVE );
drawLampsSwitch( INACTIVE );
}
void mouseInDevice( int id )
{
drawDevice(ACTIVE);
repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
}
void mouseOutDevice( int id )
{
drawDevice(INACTIVE);
repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
}
void mouseClickDevice( int id, unsigned int button )
{
selectNextDevice();
mouseInDevice( ID_DEVICE );
}
void drawDevice( int active )
{
char *color = active == ACTIVE ? DeviceColorHigh : DeviceColorLow;
drawText( devices[selected_device], disp, DeviceRect.pos.x, DeviceRect.pos.y, color );
}
void mouseInStatusSw( int id )
{
/* drawStatusSw( ACTIVE ); */
}
void mouseOutStatusSw( int id )
{
/* drawStatusSw( INACTIVE ); */
}
void mouseClickStatusSw( int id, unsigned int button )
{
if(button == 2)
pressStatusSw();
}
/* void drawStatusSw( int active ) */
void getWindowPosition( Window win, int *x, int *y )
{
XWindowAttributes winAttr;
Window dummy;
XGetWindowAttributes( dpy, win, &winAttr );
XTranslateCoordinates( dpy, win, winAttr.root,
-winAttr.border_width, -winAttr.border_width,
x, y, &dummy );
}
void getWindowDimension( Window win, int *w, int *h )
{
XWindowAttributes winAttr;
XGetWindowAttributes( dpy, win, &winAttr );
*w = winAttr.width;
*h = winAttr.height;
}
void repaint( Window win, int x, int y, int w, int h )
{
//bad code start
Pixmap src;
if( win == Win[activeWin] )
src = disp;
else if( win == Win[2] )
src = disp_info;
else {
syslog( LOG_DEBUG, "Oops! Unknown window given to repaint\n" );
return;
}
//bade code end
XCopyArea( dpy, src, win, WinGC, x, y, w, h, x, y );
XFlush(dpy);
}
void fullRepaint()
{
repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
if( infoPanelActive )
repaint( Win[2], 0, 0, InfoWinDim.w, InfoWinDim.h );
}
bool timeToUpdate()
{
static int ticker = 0;
if( ticker++ > UPDATE_INTERVAL )
{
ticker = 0;
return true;
}
return false;
}
/* get ISDN device status and update windows as needed */
void update()
{
isdnStatus stat;
getStatus( devices[selected_device], &stat );
if( memcmp(&curStatus, &stat, sizeof(stat)) != 0 )
{
memcpy( &curStatus, &stat, sizeof(stat) );
setStatusPixmap();
// drawDevice();
repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
}
updateInfoPanel();
repaint( Win[2], 0, 0, InfoWinDim.w, InfoWinDim.h );
}
/* set the appropriate pixmap on the main window */
void setStatusPixmap()
{
Pixmap statusPixmap, directionPixmap;
if( curStatus.usage > ISDN_USAGE_NONE && curStatus.usage <= ISDN_USAGE_FAX )
{
statusPixmap = statusPixmaps[curStatus.usage];
switch( curStatus.mpppMode )
{
case slave : directionPixmap = slavePixmap; break;
case master : if( curStatus.bundled == true ) { directionPixmap = bundledPixmap; break; }
if( is_slave_pending() ) { directionPixmap = bundlingPixmap; break; }
case none : directionPixmap = curStatus.direction == INCOMING ? incomingPixmap : outgoingPixmap; break;
default : syslog( LOG_DEBUG, "Ooops! curStatus.direction has an invalid value\n" ); directionPixmap = 0;
}
}
else {
switch( curStatus.usage )
{
case STAT_OFF : statusPixmap = offPixmap; break;
case ISDN_USAGE_NONE: statusPixmap = statusPixmaps[ISDN_USAGE_NONE]; break;
case STAT_DISABLED : statusPixmap = disabledPixmap; break;
case STAT_DIALING : statusPixmap = dialingPixmap; break;
case STAT_UNKNOWN : statusPixmap = unknownPixmap; break;
default : syslog( LOG_DEBUG, "Ooops! curStatus.usage has an invalid value\n" ); statusPixmap = 0;
}
directionPixmap = 0;
}
if( statusPixmap != 0 )
XCopyArea(dpy, statusPixmap, disp, WinGC, StatusPixmapRect.pos.x, StatusPixmapRect.pos.y, StatusPixmapRect.dim.w, StatusPixmapRect.dim.h, StatusPixmapRect.pos.x, StatusPixmapRect.pos.y);
if( directionPixmap != 0 )
XCopyArea(dpy, directionPixmap, disp, WinGC, DirectionPixmapRect.pos.x, DirectionPixmapRect.pos.y, DirectionPixmapRect.dim.w, DirectionPixmapRect.dim.h, DirectionPixmapRect.pos.x, DirectionPixmapRect.pos.y);
}
/* update the info panel */
void updateInfoPanel()
{
XSetForeground( dpy, WinGC, getColor(WindowBackgroundColor) );
XFillRectangle( dpy, disp_info, WinGC, 0, 0, InfoWinDim.w, InfoWinDim.h );
char line[100];
if( (curStatus.usage > ISDN_USAGE_NONE && curStatus.usage <= ISDN_USAGE_FAX) || curStatus.usage == STAT_DIALING )
{
sprintf( line, "peer phone: %s", curStatus.peerPhone );
drawText( line, disp_info, 5, 5 );
}
if( (curStatus.usage == ISDN_USAGE_NET) && (curStatus.mpppMode != slave) )
{
int a, b, c, d;
getLocalIP( &a, &b, &c, &d );
sprintf( line, "local ip : %d.%d.%d.%d", a, b, c, d );
drawText( line, disp_info, 5, 20 );
getRemoteIP( &a, &b, &c, &d );
sprintf( line, "remote ip: %d.%d.%d.%d", a, b, c, d );
drawText( line, disp_info, 5, 35 );
}
else if( curStatus.usage == STAT_OFF )
drawText( "dialing disabled", disp_info, 5, 5 );
else if( curStatus.usage == STAT_DISABLED )
drawText( "device disabled", disp_info, 5, 5 );
else if( curStatus.usage == ISDN_USAGE_NONE )
{
drawText( "not connected", disp_info, 5, 5 );
sprintf( line, "action: %s", scriptmodestrings[scriptmode] );
drawText( line, disp_info, 5, 20 );
}
switch( curStatus.mpppMode )
{
case none : sprintf( line, "bundling: none" ); break;
case master : sprintf( line, "bundling: master of %s", curStatus.mpppPartner ); break;
case slave : sprintf( line, "bundling: slave of %s", curStatus.mpppPartner ); break;
}
drawText( line, disp_info, 5, 50 );
}
void blankMainWin( int x, int y, int w, int h )
{
XCopyArea(dpy, coverPixmap, disp, WinGC, x, y, w, h, x, y);
}
unsigned long getColor( const char *colorname )
{
XColor color;
XWindowAttributes winattr;
XGetWindowAttributes(dpy, Root, &winattr);
color.pixel=0;
XParseColor(dpy, winattr.colormap, colorname, &color);
color.flags=DoRed | DoGreen | DoBlue;
XAllocColor(dpy, winattr.colormap, &color);
return color.pixel;
}
void createPixmap(char *data[], Pixmap *image, Pixmap *mask )
{
XpmAttributes pixatt;
pixatt.exactColors=false;
pixatt.closeness=40000;
pixatt.valuemask=XpmExactColors | XpmCloseness | XpmSize;
XpmCreatePixmapFromData(dpy, Root, data, image, mask, &pixatt);
}
void loadLeds( char *data[], Pixmap *image, const char *led_color, const char *back_color)
{
XpmAttributes pixatt;
unsigned long color[4];
color[0] = mixColor(led_color, 0, back_color, 100);
color[1] = mixColor(led_color, 100, back_color, 0);
color[2] = mixColor(led_color, 60, back_color, 40);
color[3] = mixColor(led_color, 25, back_color, 75);
XpmColorSymbol xpmcsym[4]={{"led_color_back", NULL, color[0] },
{"led_color_high", NULL, color[1]},
{"led_color_med", NULL, color[2]},
{"led_color_low", NULL, color[3]}};
pixatt.numsymbols = 4;
pixatt.colorsymbols = xpmcsym;
pixatt.exactColors = false;
pixatt.closeness = 40000;
pixatt.valuemask = XpmColorSymbols | XpmExactColors | XpmCloseness | XpmSize;
XpmCreatePixmapFromData(dpy, Root, data, image, NULL, &pixatt);
}
unsigned long mixColor( const char *colorname1, int prop1, const char *colorname2, int prop2 )
{
XColor color, color1, color2;
XWindowAttributes winattr;
XGetWindowAttributes(dpy, Root, &winattr);
XParseColor(dpy, winattr.colormap, colorname1, &color1);
XParseColor(dpy, winattr.colormap, colorname2, &color2);
color.pixel=0;
color.red=(color1.red*prop1+color2.red*prop2)/(prop1+prop2);
color.green=(color1.green*prop1+color2.green*prop2)/(prop1+prop2);
color.blue=(color1.blue*prop1+color2.blue*prop2)/(prop1+prop2);
color.flags=DoRed | DoGreen | DoBlue;
XAllocColor(dpy, winattr.colormap, &color);
return color.pixel;
}
/* draws text on dst using the led symbols from the leds pixmap */
void leds_drawText( char *text, Pixmap dst, int x, int y, const char *color )
{
Pixmap leds_pixmap;
loadLeds( leds_xpm, &leds_pixmap, color, WindowBackgroundColor );
x -= 3;
char *led_ptr;
while( *text != 0 )
{
led_ptr = strchr( led_text, tolower(*text) );
if( led_ptr == NULL )
{
/*syslog( LOG_DEBUG, "Oops! Internal bug in drawText: No led symbol for char %c\n", *text );*/
led_ptr = strchr( led_text, '?' );
}
XCopyArea( dpy, leds_pixmap, dst, WinGC, (led_ptr-led_text)*LedDim.w, 0, LedDim.w, LedDim.h, x, y );
x += LedDim.w;
text++;
}
XFreePixmap( dpy, leds_pixmap );
}
/* draws text on dst using the X-Font from textFont */
void font_drawText( char *text, Pixmap dst, int x, int y, const char *color )
{
XSetForeground( dpy, WinGC, getColor(color) );
XDrawImageString( dpy, dst, WinGC, x, y+textFont->ascent/2, text, strlen(text) );
}
void drawText( char *text, Pixmap dst, int x, int y, const char *color )
{
if( textFont == NULL )
leds_drawText( text, dst, x, y, color );
else
font_drawText( text, dst, x, y, color );
}
/* draws the lamp in the specified state */
void drawLamp( int lamp, int active )
{
int disp_x, disp_y, lamp_x=0;
disp_x = LampsRect[lamp].pos.x;
disp_y = LampsRect[lamp].pos.y;
/* find the offset of the lamp pixmap in the pixmap of all lamps */
for( int i=0; i < lamp; i++ )
lamp_x += LampsRect[i].dim.w*2;
lamp_x += active*LampsRect[lamp].dim.w;
XCopyArea( dpy, lampsPixmap, disp, WinGC, lamp_x, 0, LampsRect[lamp].dim.w, LampsRect[lamp].dim.h, disp_x, disp_y );
}
void isdnInitDefaultDialmode()
{
seteuid( rootUID );
setegid( rootGID );
isdn_net_ioctl_cfg cfg;
strcpy( cfg.name, devices[selected_device] );
if( isdn_ioctl( IIOCNETGCF, &cfg, NULL ) != -1 )
dialmode = cfg.dialmode;
else
dialmode = ISDN_NET_DM_AUTO; /* for the sake of cleanness, we'll get an error msg soon anyway */
if( dialmode == ISDN_NET_DM_OFF )
dialmode = ISDN_NET_DM_AUTO; /* use auto as default dialmode if device disabled */
seteuid( getuid() );
setegid( getgid() );
}
int isdn_ioctl( int func, void *arg, const char *errmsg, const char *filename )
{
int fd = fd = open( filename, O_RDONLY );
if( fd == -1 )
{
if( errmsg != NULL )
syslog( LOG_NOTICE, "Couldn't open %s : %m\n", filename );
return -1;
}
int res = ioctl( fd, func, arg );
if( res == -1 && errmsg != NULL )
syslog( LOG_NOTICE, "%s : %m\n", errmsg );
close(fd);
return res;
}
inline void isdn_dial()
{
if( !usescripts )
isdn_ioctl( IIOCNETDIL, devices[selected_device], "Couldn't dial" );
else
{
int handle;
char command[MAX_ARG_LEN];
strcpy(command, scriptpath);
strcat(command, "/");
strcat(command, SCRIPT_UP);
if ((handle = open(command, O_RDONLY)) == -1)
syslog( LOG_NOTICE, "Couldn't open %s : %m\n", SCRIPT_UP );
else {
close(handle);
sprintf(command, "%s/%s %s %d 2>&1 | logger -t wmisdn.sh &", scriptpath, SCRIPT_UP, devices[selected_device], scriptmode);
system(command);
}
}
update();
}
inline void isdn_hangup()
{
if( !usescripts )
isdn_ioctl( IIOCNETHUP, devices[selected_device], "Couldn't hang up" );
else
{
int handle;
char command[MAX_ARG_LEN];
strcpy(command, scriptpath);
strcat(command, "/");
strcat(command, SCRIPT_DOWN);
if ((handle = open(command, O_RDONLY)) == -1)
syslog( LOG_NOTICE, "Couldn't open %s : %m\n", SCRIPT_DOWN );
else {
close(handle);
sprintf(command, "%s/%s %s %d 2>&1 | logger -t wmisdn.sh &", scriptpath, SCRIPT_DOWN, devices[selected_device], scriptmode);
system(command);
}
}
update();
}
inline void isdn_enable()
{
isdn_net_ioctl_cfg cfg;
strcpy( cfg.name, devices[selected_device] );
if( isdn_ioctl( IIOCNETGCF, &cfg, "Error enabling dialing. Couldn't get dev cfg" ) != -1 )
{
cfg.dialmode = dialmode;
isdn_ioctl( IIOCNETSCF, &cfg, "Error enabling dialing. Couldn't set dev cfg" );
}
}
inline void isdn_disable()
{
isdn_net_ioctl_cfg cfg;
strcpy( cfg.name, devices[selected_device] );
if( isdn_ioctl( IIOCNETGCF, &cfg, "Error disabling dialing. Couldn't get dev cfg" ) != -1 )
{
cfg.dialmode = ISDN_NET_DM_OFF;
isdn_ioctl( IIOCNETSCF, &cfg, "Error disabling dialing. Couldn't set dev cfg" );
}
}
inline void isdn_dial_slave( char *master )
{
isdn_ioctl( IIOCNETALN, master, "Couldn't fire up slave" );
}
inline void isdn_hangup_slave( char *master )
{
isdn_ioctl( IIOCNETDLN, master, "Couldn't hang up slave" );
}
inline void set_slave_pending()
{
slave_pending = devices[selected_device];
}
inline void clear_slave_pending()
{
slave_pending = NULL;
}
inline bool is_slave_pending()
{
return slave_pending != NULL;
}
inline void manage_slave()
{
if( is_slave_pending() )
{
if( curStatus.usage == ISDN_USAGE_NET )
{
isdn_dial_slave(slave_pending);
clear_slave_pending();
}
if( curStatus.usage == ISDN_USAGE_NONE )
clear_slave_pending();
}
}
/* react upon a lamp press
* - green opens a connection and sets the device in dial_auto mode
* - yellow ends the connection and sets the device in dial_auto mode
* - red ends the connection and sets the device in dial_off mode
*/
inline void _pressGreenLamp( int button )
{
/* middle button - just change the script mode */
if( button == 2 )
{
advanceScriptMode();
return;
}
/* online request of slave - add a channel to the master */
if( curStatus.mpppMode == slave )
isdn_dial_slave( curStatus.mpppPartner );
/* online request of master or non-bundled device */
else {
/* additional mppp-link requested - add a slave channel to the master (wait until master online) */
if( (button == 3) && (curStatus.mpppMode == master) )
set_slave_pending();
/* if device is dialing or online - ignore button */
if( curStatus.usage == STAT_DIALING || curStatus.usage == ISDN_USAGE_NET )
return;
if( curStatus.usage == STAT_OFF )
isdn_enable();
isdn_dial();
}
}
inline void _pressYellowLamp( int button )
{
if( curStatus.usage == ISDN_USAGE_NONE )
return;
if( curStatus.usage == STAT_OFF )
isdn_enable();
else
{
if( (button == 3) || (button == 1) && (curStatus.mpppMode == master) )
isdn_hangup_slave( devices[selected_device] );
if( button == 1 )
{
if( curStatus.mpppMode == slave )
isdn_hangup_slave( curStatus.mpppPartner );
else
isdn_hangup();
}
}
}
inline void _pressRedLamp( int button )
{
if( (curStatus.usage == STAT_OFF) || (button != 1) )
return;
_pressYellowLamp( button );
isdn_disable();
}
void pressLamp( int lamp_id, int button )
{
seteuid( rootUID );
setegid( rootGID );
switch( lamp_id )
{
case ID_LAMP_GREEN : _pressGreenLamp( button );break;
case ID_LAMP_YELLOW : _pressYellowLamp( button ); break;
case ID_LAMP_RED : _pressRedLamp( button ); break;
}
seteuid( getuid() );
setegid( getgid() );
}
/* activated when user clicks the status pixmap with the right button - switch online<->offline */
void pressStatusSw()
{
seteuid( rootUID );
setegid( rootGID );
if( curStatus.usage == ISDN_USAGE_NONE )
_pressGreenLamp(1);
else if(curStatus.usage == ISDN_USAGE_NET )
_pressYellowLamp(1);
seteuid( getuid() );
setegid( getgid() );
}
/* Get the local/remote IP addresses of the devices[selected_device] */
void getLocalIP( int *a, int *b, int *c, int *d )
{
struct ifreq ifr;
int fd = socket( AF_INET, SOCK_DGRAM, 0 );
strcpy( ifr.ifr_ifrn.ifrn_name, devices[selected_device] );
ifr.ifr_ifru.ifru_addr.sa_family = AF_INET;
int res = ioctl(fd, SIOCGIFADDR, &ifr);
close(fd);
translateIP( &(ifr.ifr_ifru.ifru_addr), a, b, c, d );
if( res != 0 )
syslog( LOG_NOTICE, "Oops! Couldn't get local IP of device %s. ioctl() call failed : %m\n", devices[selected_device] );
}
void getRemoteIP( int *a, int *b, int *c, int *d )
{
struct ifreq ifr;
int fd = socket( AF_INET, SOCK_DGRAM, 0 );
strcpy( ifr.ifr_ifrn.ifrn_name, devices[selected_device] );
ifr.ifr_ifru.ifru_addr.sa_family = AF_INET;
int res = ioctl( fd, SIOCGIFDSTADDR, &ifr );
close(fd);
translateIP( &(ifr.ifr_ifru.ifru_addr), a, b, c, d );
if( res != 0 )
syslog( LOG_NOTICE, "Oops! Couldn't get remote IP of device %s. ioctl() call failed : %m\n", devices[selected_device]);
}
/* extract the ip address from the addr struct asuming that it is a valid INET sockaddr */
inline void translateIP( struct sockaddr *addr, int *a, int *b, int *c, int *d )
{
struct sockaddr_in* inet_addr = (sockaddr_in *)addr;
unsigned int ip = inet_addr->sin_addr.s_addr;
*d = (ip >> 24) & 0xFF;
*c = (ip >> 16) & 0xFF;
*b = (ip >> 8 ) & 0xFF;
*a = ip & 0xFF;
}
/* extract the data from the 'key'-line of /dev/isdninfo for all 16 B-Channels */
bool extractIsdnInfoData( const char *all_data, const char *key, char buffer[ISDN_MAX_CHANNELS][100] )
{
char temp[100]; /* buffer the key string */
char *ptr;
ptr = strstr( all_data, key );
if( ptr == NULL )
{
syslog( LOG_NOTICE, "Error getting status info. /dev/isdninfo doesn't contain a '%s' line\n", key );
return false;
}
sscanf( ptr, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
temp,
buffer[0], buffer[1], buffer[2], buffer[3],
buffer[4], buffer[5], buffer[6], buffer[7],
buffer[8], buffer[9], buffer[10], buffer[11],
buffer[12], buffer[13], buffer[14], buffer[15] );
return true;
}
bool getPeerPhone( char *ippp, char *phone )
{
isdn_net_ioctl_phone ippp_phone;
int res;
strcpy( ippp_phone.name, ippp );
res = isdn_ioctl( IIOCNETGPN, &ippp_phone, NULL, "/dev/isdninfo" );
if( res < 0 )
{
if( errno != ENOTCONN ) /* device not connected - no real error */
syslog( LOG_NOTICE, "Error getting phone number for device %s: %m", ippp );
return false;
}
strcpy( phone, ippp_phone.phone );
return true;
}
bool findBChannel( char *phone, char all_phones[ISDN_MAX_CHANNELS][100], int &channel )
{
for( int i=0; i < ISDN_MAX_CHANNELS; i++ )
if( strcmp( all_phones[i], phone ) == 0 )
{
channel = i;
return true;
}
syslog( LOG_NOTICE, "Hmm!!?? That's strange! Device phone number %s couldn't be found in /dev/isdninfo", phone );
return false;
}
void getMPPPSettings( isdn_net_ioctl_cfg *cfg, isdnStatus *stat )
{
stat->mpppMode = none;
if( strlen(cfg->master) != 0 )
{
stat->mpppMode = slave;
strcpy( stat->mpppPartner, cfg->master );
}
if( strlen(cfg->slave) != 0 )
{
stat->mpppMode = master;
strcpy( stat->mpppPartner, cfg->slave );
}
}
/* get the status of the ippp device:
*
* - isOff if dialing is disabled
* - isOffline if dialing is enabled but no connection is established
* - isOnline if device has established a connection
* - isDialing if device is dialing the remote but no connection is established
* - isUnknown if no stat info available
*/
void getStatus( char *device, isdnStatus *stat )
{
isdn_net_ioctl_cfg cfg;
int fd, len, res;
char buf[10000];
static int warning_count=0;
int channel, channel_usage;
char channel_info[ISDN_MAX_CHANNELS][100];
/* get ippp device config */
seteuid( rootUID );
setegid( rootGID );
strcpy( cfg.name, device );
res = isdn_ioctl( IIOCNETGCF, &cfg, warning_count < STATUS_WARNING_SAT ? "Error getting status info. Couldn't get device cfg" : (char *)NULL );
seteuid( getuid() );
setegid( getgid() );
stat->usage = STAT_UNKNOWN;
stat->direction = INCOMING;
if( res == -1 )
{
warning_count++;
return;
}
warning_count = 0;
if( cfg.dialmode == ISDN_NET_DM_OFF )
stat->usage = STAT_OFF;
else
stat->usage = ISDN_USAGE_NONE;
stat->bundled = false;
getMPPPSettings( &cfg, stat );
/* read the device flags from /dev/isdninfo */
fd = open( "/dev/isdninfo", O_RDONLY|O_NDELAY );
if( fd == -1 )
{
syslog( LOG_NOTICE, "Error getting status info. Couldn't open /dev/isdninfo : %m\n" );
return;
}
len = read( fd, buf, sizeof(buf)-1 );
close(fd);
if( len == -1 )
{
syslog( LOG_NOTICE, "Error getting status info. Couldn't read from /dev/isdninfo : %m\n" );
return;
}
buf[len] = 0; /* terminate the string */
if( !extractIsdnInfoData( buf, "phone:", channel_info ) )
return;
if( !getPeerPhone( device, stat->peerPhone ) )
return;
if( !findBChannel( stat->peerPhone, channel_info, channel ) )
return;
if( !extractIsdnInfoData( buf, "usage:", channel_info ) )
return;
channel_usage = atoi(channel_info[channel]);
if( (channel_usage & ISDN_USAGE_DISABLED) != 0 )
stat->usage = STAT_DISABLED;
else
stat->usage = channel_usage & ISDN_USAGE_MASK;
stat->direction = (channel_usage & ISDN_USAGE_OUTGOING) == 0 ? INCOMING : OUTGOING;
/* check if device is still dialing or already online */
if( stat->usage == ISDN_USAGE_NET )
{
if( !extractIsdnInfoData( buf, "flags:", channel_info ) )
return;
if( ((atoi(channel_info[0]) >> channel) & 1) == 0 )
stat->usage = STAT_DIALING;
}
/* check for channel bundling */
if( stat->mpppMode == master )
{
isdnStatus slaveStatus;
getStatus( stat->mpppPartner, &slaveStatus );
if( (stat->usage == slaveStatus.usage) && (stat->direction == slaveStatus.direction) &&
(strcmp(stat->peerPhone,slaveStatus.peerPhone)==0) )
stat->bundled = true;
}
}