/* 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for ENOTCONN */ #include #include #include #include #include #include #include #include #include #include #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 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 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 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 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; } }