wmbiff: fixed possible null-pointer dereference.
[dockapps.git] / wmisdn / wmisdn.cc
blobe7f4174fdc14ad186c612924a11a36913c794d39
1 /* wmisdn - an ISDN monitor applet for windowmaker/afterstep
2 * Copyright (c) 2000-2001 Tasho Statev Kaletha
3 * tasho.kaletha@gmx.de
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 /* these defaults can be changed by command line options. */
19 #define WINDOWMAKER false
20 #define USESHAPE false
21 #define NAME "wmisdn"
22 #define CLASS "WMIsdn"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <ctype.h>
29 #include <math.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <net/if.h>
37 #include <netinet/in.h>
38 #include <syslog.h>
39 #include <asm/errno.h> /* for ENOTCONN */
40 #include <errno.h>
42 #include <X11/X.h>
43 #include <X11/Xlib.h>
44 #include <X11/Xutil.h>
45 #include <X11/Xproto.h>
46 #include <X11/xpm.h>
47 #include <X11/extensions/shape.h>
49 #include <linux/isdn.h>
50 #include <linux/isdnif.h>
51 #include <time.h>
53 #include "regions.h"
54 #include "optics/optics.h"
56 static Pixmap coverPixmap;
57 static Pixmap unknownPixmap;
58 static Pixmap dialingPixmap;
59 static Pixmap offPixmap;
60 static Pixmap disabledPixmap;
61 static Pixmap statusPixmaps[6];
62 static Pixmap incomingPixmap, outgoingPixmap, bundlingPixmap, bundledPixmap, slavePixmap;
65 static Pixmap ledsPixmap; /* a row of led symbols as shown by the var led_text below */
66 static Pixmap lampsPixmap; /* a row of lamp images - green off, green on, yellow off, yellow on, red off, red on */
67 static Pixmap infoSWPixmap; /* a row of arrows - left off, left on, right off, right on */
68 static Pixmap lampsSWPixmap; /* a row of arrows - up off, up on, down off, down on */
70 #include "xpm/unknown.xpm"
71 #include "xpm/disabled.xpm"
72 #include "xpm/off.xpm"
73 #include "xpm/offline.xpm"
74 #include "xpm/dialing.xpm"
75 #include "xpm/incoming.xpm"
76 #include "xpm/outgoing.xpm"
77 #include "xpm/bundling.xpm"
78 #include "xpm/bundled.xpm"
79 #include "xpm/slave.xpm"
80 #include "xpm/raw.xpm"
81 #include "xpm/modem.xpm"
82 #include "xpm/online.xpm"
83 #include "xpm/voice.xpm"
84 #include "xpm/fax.xpm"
86 #include "xpm/cover.xpm"
87 #include "xpm/leds.xpm"
88 #include "xpm/lamps.xpm"
89 #include "xpm/lamps_sw.xpm"
90 #include "xpm/info_sw.xpm"
92 /* Runtime pixmaps */
93 static Pixmap disp_info; /* double buffer for the info panel */
94 static Pixmap disp; /* for the main window */
95 static Pixmap dmsk; /* clip mask for the main window */
97 /* For command line arguments */
98 #define MAX_ARG_LEN 256
99 static bool wmaker = WINDOWMAKER;
100 static bool ushape = USESHAPE;
101 static char txtdpy[MAX_ARG_LEN] = "";
102 static char txtfont[MAX_ARG_LEN] = "";
103 static int dialmode = ISDN_NET_DM_AUTO;
104 static char devices[ISDN_MAX_CHANNELS][MAX_ARG_LEN];
105 static int selected_device=-1; /* selected device, points to an element of devices[] */
106 static char scriptpath[MAX_ARG_LEN] = "/etc/isdn";
107 static int scriptmode = 0;
108 static bool usescripts = false;
109 static int maxscriptmode = 0;
110 static char** scriptmodestrings = NULL;
111 static char *slave_pending = NULL;
113 /* atoms for deleting window */
114 static Atom _XA_GNUSTEP_WM_FUNC;
115 static Atom WM_DELETE_WINDOW;
117 /* global variables */
118 Display *dpy;
119 Window Win[3]; /* 0 - main win, 1 - icon win (for wmaker), 2 - info panel */
120 Window Root;
121 GC WinGC;
122 int activeWin;
123 XFontStruct *textFont=NULL;
125 static char led_text[] = "0123456789?/\\!@#$%^&*()_+-=\"~<>[]{}:. abcdefghijklmnopqrstuvwxyz";
128 static int rootUID, rootGID;
129 static bool infoPanelActive = false;
130 static bool lampsActive = false;
132 /* Der scriptmode wird als 2. Argument den Start-/Stopskripten uebergeben.
133 Aenderung mit mittlerer Maustaste auf InfoSw bei offenem Infopanel. */
135 #define ACTIVE 1 /* values are not only symbolc, but important for calculations! */
136 #define INACTIVE 0
137 #define ID_LAMP_GREEN 0
138 #define ID_LAMP_YELLOW 1
139 #define ID_LAMP_RED 2
141 #define ID_SWITCH_INFO 10
142 #define ID_SWITCH_LAMPS 11
143 #define ID_SWITCH_STATUS 19
144 #define ID_DEVICE 20
146 #define UPDATE_INTERVAL 20 /* how many 50 milisec intervalls to wait between updates */
147 #define STATUS_WARNING_SAT 5 /* how many times to display a warning upon failing to retrieve device stats */
149 #define INCOMING 0
150 #define OUTGOING 1
151 #define STAT_DISABLED 1000
152 #define STAT_OFF 1001
153 #define STAT_DIALING 1002
154 #define STAT_UNKNOWN 2001
155 #define STAT_UNINITIALIZED 2002
157 #define SCRIPT_UP "wmisdn-up"
158 #define SCRIPT_DOWN "wmisdn-down"
159 #define SCRIPT_MODES "wmisdn-scriptmodes"
161 typedef enum mpppModeType { none, master, slave };
163 struct isdnStatus
165 int usage;
166 int direction;
167 bool bundled;
168 char peerPhone[100];
169 mpppModeType mpppMode;
170 char mpppPartner[100];
171 } curStatus = { STAT_UNINITIALIZED, INCOMING, false, "", none, "" };
175 /* text i/o routines */
176 bool scanArgs(int argc, char *argv[]);
177 void printUsage( char *prog_name );
178 void printHeader();
179 void parseDeviceNames( char *name_list );
180 void readScriptModes();
183 /* init/done routines */
184 void initXWin(int argc, char *argv[]);
185 void freeXWin();
186 void createMainWin( Window *win );
187 void createInfoPanel( Window *win );
188 void loadPixmaps();
189 void freePixmaps();
190 void createRegions();
193 /* window routines */
194 void alignInfoPanel();
195 void getWindowPosition( Window win, int *x, int *y );
196 void getWindowDimension( Window win, int *w, int *h );
198 /* graphic routines */
199 unsigned long getColor(const char *colorname);
200 void createPixmap(char *data[], Pixmap *image, Pixmap *mask );
201 void loadLeds(char *data[], Pixmap *image, const char *leds_color, const char *back_color );
202 void drawText( char *text, Pixmap dst, int x, int y, const char *color=InfoTextColor );
203 void drawLamp( int index, int active );
204 void drawDevice( int active = INACTIVE );
205 unsigned long mixColor( const char *colorname1, int prop1, const char *colorname2, int prop2);
207 /* interaction routines */
208 bool timeToUpdate();
209 void update();
210 void fullRepaint();
211 void repaint( Window win, int x, int y, int w, int h );
212 void setStatusPixmap();
213 void updateInfoPanel();
214 void blankMainWin( int x=0, int y=0, int w=MainWinDim.w, int h=MainWinDim.h );
215 void pressLamp( int lamp, int button );
216 void pressStatusSw();
217 void activateLamps( bool active );
218 void drawSwitches();
220 /* region event handlers */
221 void mouseInLamp( int id );
222 void mouseOutLamp( int id );
223 void mouseClickLamp( int id, unsigned int button );
224 void mouseInInfoSw( int id );
225 void mouseOutInfoSw( int id );
226 void mouseClickInfoSw( int id, unsigned int button );
227 void mouseInLampsSw( int id );
228 void mouseOutLampsSw( int id );
229 void mouseClickLampsSw( int id, unsigned int button );
230 void mouseInDevice( int id );
231 void mouseOutDevice( int id );
232 void mouseClickDevice( int id, unsigned int button );
233 void mouseInStatusSw( int id );
234 void mouseOutStatusSw( int id );
235 void mouseClickStatusSw( int id, unsigned int button );
238 void selectNextDevice();
240 /* event handlers */
241 void exposeEvent( XExposeEvent *xev);
242 void pressEvent(XButtonEvent *xev);
243 void motionEvent( XMotionEvent *xev );
245 /* ISDN routines */
246 void getStatus( char *device, isdnStatus *stat );
247 void getLocalIP( int *a, int *b, int *c, int *d );
248 inline void getRemoteIP( int *a, int *b, int *c, int *d );
249 inline void translateIP( struct sockaddr *addr, int *a, int *b, int *c, int *d );
250 int isdn_ioctl( int func, void *arg, const char *errmsg, const char *filename="/dev/isdnctrl" );
251 void isdnInitDefaultDialmode();
252 int getIpppNum( char *name );
254 inline void set_slave_pending();
255 inline void clear_slave_pending();
256 inline bool is_slave_pending();
257 inline void manage_slave();
259 /* -------- Implementation ----------- */
261 int main(int argc, char *argv[])
264 rootUID = geteuid(); rootGID = getegid();
265 seteuid(getuid()); setegid(getgid());
267 printHeader();
268 if( !scanArgs(argc, argv) )
270 printUsage( argv[0] );
271 return 1;
273 readScriptModes();
275 initXWin(argc, argv);
277 loadPixmaps();
278 createRegions();
279 disp = XCreatePixmap(dpy, Root, MainWinDim.w, MainWinDim.h, DefaultDepth(dpy,DefaultScreen(dpy)));
280 disp_info = XCreatePixmap(dpy, Root, InfoWinDim.w, InfoWinDim.h, DefaultDepth(dpy,DefaultScreen(dpy)));
282 XGCValues gcv;
283 unsigned long gcm;
284 gcm = GCGraphicsExposures|GCBackground;
285 gcv.graphics_exposures = True;
286 gcv.background = getColor( WindowBackgroundColor );
287 if( strlen(txtfont) != 0 )
289 textFont = XLoadQueryFont( dpy, txtfont );
290 if( textFont != NULL )
292 gcm |= GCFont;
293 gcv.font = textFont->fid;
294 } else
295 syslog( LOG_NOTICE, "Couldn't load specified font" );
297 WinGC = XCreateGC(dpy, Root, gcm, &gcv);
299 blankMainWin();
300 drawDevice(INACTIVE);
301 activateLamps( lampsActive );
302 drawSwitches();
303 update();
305 if(!(wmaker || ushape))
306 XSetClipMask(dpy, WinGC, dmsk);
307 else
308 XShapeCombineMask(dpy, Win[activeWin], ShapeBounding, 0, 0, dmsk, ShapeSet);
310 XSetClipOrigin(dpy, WinGC, 0, 0);
311 XSetClipMask(dpy, WinGC, None);
313 XEvent event;
314 XSelectInput(dpy, Win[activeWin], PointerMotionMask | ButtonPress | ExposureMask);
315 XSelectInput(dpy, Win[2], ExposureMask );
316 XMapWindow(dpy, Win[0]);
318 bool finished=false;
319 while(!finished){
320 while(XPending(dpy)){
321 XNextEvent(dpy,&event);
322 switch(event.type){
323 case ButtonPress : pressEvent(&event.xbutton); break;
324 case MotionNotify : motionEvent(&event.xmotion); break;
326 case ClientMessage :
327 if((Atom)event.xclient.data.l[0]==WM_DELETE_WINDOW)
328 finished=true;
329 break;
331 case Expose : exposeEvent( &event.xexpose ); break;
334 if( timeToUpdate() )
336 update();
337 manage_slave();
339 usleep(50000);
342 if( textFont != NULL )
343 XFreeFont( dpy, textFont );
344 XFreeGC(dpy, WinGC);
345 freePixmaps();
346 /* Free runtime pixmaps */
347 XFreePixmap(dpy, disp_info);
348 XFreePixmap(dpy, disp);
349 XFreePixmap(dpy, dmsk);
350 /* Finish with X stuff */
351 freeXWin();
352 return 0;
355 void initXWin(int argc, char *argv[])
357 if( (dpy=XOpenDisplay(txtdpy)) == NULL )
359 fprintf(stderr,"cannot open display!\n");
360 exit(1);
362 _XA_GNUSTEP_WM_FUNC = XInternAtom(dpy, "_GNUSTEP_WM_FUNCTION", false);
363 WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
364 Root=DefaultRootWindow(dpy);
365 createMainWin(&Win[0]);
366 createMainWin(&Win[1]);
367 createInfoPanel( &Win[2] );
368 XWMHints hints;
369 XSizeHints shints;
370 hints.window_group = Win[0];
371 shints.min_width=64;
372 shints.min_height=64;
373 shints.max_width=64;
374 shints.max_height=64;
375 shints.x=0;
376 shints.y=0;
377 if(wmaker)
379 hints.initial_state = WithdrawnState;
380 hints.icon_window = Win[1];
381 hints.flags = WindowGroupHint | StateHint | IconWindowHint;
382 shints.flags = PMinSize | PMaxSize | PPosition;
383 activeWin=1;
385 else {
386 hints.initial_state = NormalState;
387 hints.flags = WindowGroupHint | StateHint;
388 shints.flags = PMinSize | PMaxSize;
389 activeWin=0;
391 XSetWMHints(dpy, Win[0], &hints);
392 XSetWMNormalHints(dpy, Win[0], &shints);
393 XSetCommand(dpy, Win[0], argv, argc);
394 XStoreName(dpy, Win[0], NAME);
395 XSetIconName(dpy, Win[0], NAME);
396 XSetWMProtocols(dpy, Win[activeWin], &WM_DELETE_WINDOW, 1);
399 void freeXWin()
401 XDestroyWindow(dpy, Win[0]);
402 XDestroyWindow(dpy, Win[1]);
403 XDestroyWindow(dpy, Win[2]);
404 XCloseDisplay(dpy);
407 void loadPixmaps()
409 createPixmap(cover_xpm, &coverPixmap, &dmsk );
410 createPixmap(dialing_xpm, &dialingPixmap, NULL );
411 createPixmap(unknown_xpm, &unknownPixmap, NULL );
412 createPixmap(disabled_xpm, &disabledPixmap, NULL );
413 createPixmap(off_xpm, &offPixmap, NULL );
415 createPixmap(incoming_xpm, &incomingPixmap, NULL );
416 createPixmap(outgoing_xpm, &outgoingPixmap, NULL );
417 createPixmap(bundling_xpm, &bundlingPixmap, NULL );
418 createPixmap(bundled_xpm, &bundledPixmap, NULL );
419 createPixmap(slave_xpm, &slavePixmap, NULL );
421 createPixmap(offline_xpm, &statusPixmaps[ISDN_USAGE_NONE], NULL );
422 createPixmap(raw_xpm, &statusPixmaps[ISDN_USAGE_RAW], NULL );
423 createPixmap(modem_xpm, &statusPixmaps[ISDN_USAGE_MODEM], NULL );
424 createPixmap(online_xpm, &statusPixmaps[ISDN_USAGE_NET], NULL );
425 createPixmap(voice_xpm, &statusPixmaps[ISDN_USAGE_VOICE], NULL );
426 createPixmap(fax_xpm, &statusPixmaps[ISDN_USAGE_FAX], NULL );
428 createPixmap(lamps_xpm, &lampsPixmap, NULL );
429 createPixmap(info_sw_xpm, &infoSWPixmap, NULL );
430 createPixmap(lamps_sw_xpm, &lampsSWPixmap, NULL );
431 loadLeds( leds_xpm, &ledsPixmap, InfoTextColor, WindowBackgroundColor );
434 void freePixmaps()
436 XFreePixmap(dpy, coverPixmap);
437 XFreePixmap(dpy, dialingPixmap);
438 XFreePixmap(dpy, unknownPixmap);
439 XFreePixmap(dpy, disabledPixmap);
440 XFreePixmap(dpy, offPixmap);
442 XFreePixmap(dpy, incomingPixmap);
443 XFreePixmap(dpy, outgoingPixmap);
444 XFreePixmap(dpy, bundlingPixmap);
445 XFreePixmap(dpy, bundledPixmap);
446 XFreePixmap(dpy, slavePixmap);
448 for( int i=ISDN_USAGE_NONE; i < ISDN_USAGE_FAX; i++ )
449 XFreePixmap( dpy, statusPixmaps[i] );
451 XFreePixmap(dpy, ledsPixmap);
452 XFreePixmap(dpy, lampsPixmap);
453 XFreePixmap(dpy, infoSWPixmap);
454 XFreePixmap(dpy, lampsSWPixmap);
457 void createMainWin( Window *win )
459 *win = XCreateSimpleWindow(dpy, Root, 10, 10, MainWinDim.w, MainWinDim.h,0,0,0);
461 XClassHint classHint;
462 classHint.res_name = NAME;
463 classHint.res_class = CLASS;
464 XSetClassHint(dpy, *win, &classHint);
467 void createInfoPanel( Window *win )
469 *win = XCreateSimpleWindow(dpy, Root, 10, 10, InfoWinDim.w, InfoWinDim.h,0,0,0);
471 XSizeHints shints;
472 shints.flags = PPosition;
473 XSetWMNormalHints( dpy, *win, &shints );
475 XClassHint classHint;
476 classHint.res_name = "Info";
477 classHint.res_class = CLASS;
478 XSetClassHint(dpy, *win, &classHint);
481 void createRegions()
483 region_init(dpy);
485 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 );
486 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 );
487 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 );
489 region_add( Win[activeWin], ID_SWITCH_INFO, InfoSWRect.pos.x, InfoSWRect.pos.y, InfoSWRect.dim.w, InfoSWRect.dim.h, mouseInInfoSw, mouseOutInfoSw, mouseClickInfoSw );
490 region_add( Win[activeWin], ID_SWITCH_LAMPS, LampsSWRect.pos.x, LampsSWRect.pos.y, LampsSWRect.dim.w, LampsSWRect.dim.h, mouseInLampsSw, mouseOutLampsSw, mouseClickLampsSw );
492 region_add( Win[activeWin], ID_DEVICE, DeviceRect.pos.x, DeviceRect.pos.y, DeviceRect.dim.w, DeviceRect.dim.h, mouseInDevice, mouseOutDevice, mouseClickDevice );
493 region_add( Win[activeWin], ID_SWITCH_STATUS, StatusPixmapRect.pos.x, StatusPixmapRect.pos.y, StatusPixmapRect.dim.w, StatusPixmapRect.dim.h, mouseInStatusSw, mouseOutStatusSw, mouseClickStatusSw );
496 bool validIppp( char *name )
498 if( strlen(name) < 5 )
499 return false;
500 if( strncmp( name, "ippp", 4 ) != 0 )
501 return false;
502 for( char *p=name+4; *p != '\x0'; p++ )
503 if( !isdigit(*p) )
504 return false;
505 if( getIpppNum(name) >= ISDN_MAX_CHANNELS )
506 return false;
507 return true;
510 int getIpppNum( char *name )
512 return atoi( name + 4 );
515 void selectNextDevice()
517 selected_device++;
518 if( devices[selected_device][0] == 0 )
519 selected_device = 0;
520 drawDevice();
521 update();
524 void printUsage( char *prog_name )
526 fprintf( stderr, "usage:\n\n %s [options]\n\noptions:\n\n", prog_name );
527 fprintf( stderr, " -h | -help | --help display this help screen\n");
528 fprintf( stderr, " -w use WithdrawnState (for WindowMaker)\n" );
529 fprintf( stderr, " -s shaped window\n" );
530 fprintf( stderr, " -display display select target display (see X manual pages)\n" );
531 fprintf( stderr, " -font font select the font for displaying status information\n" );
532 fprintf( stderr, " -dialmode mode select dial mode for offline mode (auto or manual)\n" );
533 fprintf( stderr, " -device device select ippp devices to monitor\n" );
534 fprintf( stderr, " (a list of comma-separated device names is expected containing __no blanks__)\n" );
535 fprintf( stderr, " -lamps activate the line control switches upon startup\n" );
536 fprintf( stderr, " -usescripts use user scripts for dialing/hanging up instead of direct ioctl calls\n" );
537 fprintf( stderr, " -path path select directory with the up-/down-scripts\n\n" );
540 void printHeader()
542 fprintf( stderr, "wmisdn v1.8 (C) 1999-2001 Tasho Statev Kaletha (kaletha@informatik.uni-bonn.de).\n\n" );
545 void parseDeviceNames( char *name_list )
547 char *ptr1, *ptr2;
548 int i;
550 ptr1 = name_list;
552 for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
554 ptr2 = strchr(ptr1,',');
555 if( ptr2 == NULL )
556 ptr2 = &name_list[strlen(name_list)];
557 strncpy( devices[i], ptr1, ptr2-ptr1 );
558 devices[i][ptr2-ptr1] = 0;
559 devices[i+1][0] = 0;
560 if( !validIppp(devices[i]) )
561 fprintf( stderr, "Warning : \"%s\" doesn't seem to be a valid ippp device. wmisdn may not work properly\n", devices[i] );
562 if( ptr2[0] == 0 )
563 return;
564 ptr1 = ptr2+1;
569 bool scanArgs(int argc, char *argv[])
571 bool dialmode_set = false;
573 for(int i=1;i<argc;i++)
575 if(strcmp(argv[i],"-h")==0 || strcmp(argv[i],"-help")==0 || strcmp(argv[i],"--help")==0)
576 return false;
578 else if(strcmp(argv[i],"-w")==0)
579 wmaker=true;
580 else if(strcmp(argv[i],"-s")==0)
581 ushape=true;
582 else if(strcmp(argv[i],"-lamps")==0)
583 lampsActive=true;
584 else if(strcmp(argv[i],"-usescripts")==0)
585 usescripts=true;
587 else if(strcmp(argv[i],"-display")==0)
589 if(i<argc-1)
591 i++;
592 if( strlen(argv[i]) > MAX_ARG_LEN-1 )
594 fprintf( stderr, "Argument for -display option too long\n" );
595 return false;
597 sprintf(txtdpy,"%s",argv[i]);
599 continue;
601 else if(strcmp(argv[i],"-font")==0)
603 if(i<argc-1)
605 i++;
606 if( strlen(argv[i]) > MAX_ARG_LEN-1 )
608 fprintf( stderr, "Argument for -font option too long\n" );
609 return false;
611 sprintf(txtfont,"%s",argv[i]);
613 continue;
615 else if(strcmp(argv[i],"-dialmode")==0)
617 if(i<argc-1)
619 i++;
620 if( strcmp(argv[i], "auto")==0 )
621 dialmode = ISDN_NET_DM_AUTO;
622 else if( strcmp(argv[i], "manual")==0 )
623 dialmode = ISDN_NET_DM_MANUAL;
624 else {
625 fprintf( stderr, "Unknown dial mode \"%s\"\n", argv[i] );
626 return false;
628 dialmode_set = true;
631 else if(strcmp(argv[i],"-device")==0)
633 if(i<argc-1)
635 i++;
636 if( strlen(argv[i]) > MAX_ARG_LEN-1 )
638 fprintf( stderr, "Argument for -device option too long\n" );
639 return false;
641 parseDeviceNames( argv[i] );
642 selected_device = 0;
645 else if(strcmp(argv[i],"-path")==0)
647 if(i<argc-1)
649 i++;
650 if( strlen(argv[i]) > MAX_ARG_LEN-1 )
652 fprintf( stderr, "Argument for -path option too long\n" );
653 return false;
655 strcpy( scriptpath, argv[i] );
658 else {
659 fprintf( stderr, "Unknown option \"%s\"\n", argv[i] );
660 return false;
664 if( !dialmode_set )
665 isdnInitDefaultDialmode();
666 if( selected_device == -1 )
668 strcpy( devices[0], "ippp0" );
669 devices[1][0] = 0;
670 selected_device = 0;
673 return true;
676 /* Reads the string representations of the scriptmode parameter given to the up/down scripts
677 * and initializes the coresponding variables */
678 void readScriptModes()
680 char filename[1000];
681 char buf[1000];
682 sprintf( filename, "%s/%s", scriptpath, SCRIPT_MODES );
683 FILE *f = fopen( filename, "r" );
684 /* init one default string if reading fails */
685 if( f == NULL || (fgets(buf,sizeof(buf),f) == NULL) || !usescripts )
687 maxscriptmode = 0;
688 if( usescripts )
689 syslog( LOG_NOTICE, "Couldn't read script mode strings: %m" );
690 scriptmodestrings = (char **)malloc( sizeof(char*) );
691 scriptmodestrings[0] = (char *)malloc( sizeof("go online") );
692 strcpy(scriptmodestrings[0], "go online" );
693 if( f != NULL )
694 fclose(f);
695 return;
697 maxscriptmode = -1; /* the first iteration sets it to 0 - first array index */
699 /* read the strings and put them into the scriptmodestrings array */
702 maxscriptmode++;
703 scriptmodestrings = (char **)realloc( scriptmodestrings, (maxscriptmode+1)*sizeof(char*) );
704 scriptmodestrings[maxscriptmode] = (char *)malloc( strlen(buf)+1 );
705 while( strchr(buf,'\n') != NULL )
706 *strchr(buf,'\n') = '\0';
707 strcpy( scriptmodestrings[maxscriptmode], buf );
708 } while( fgets(buf,sizeof(buf),f) != NULL );
709 fclose(f);
712 void advanceScriptMode()
714 scriptmode++;
715 if(scriptmode > maxscriptmode)
716 scriptmode = 0;
717 update();
720 /* press event
721 * - if a lamp is pressed then the corresponding actions are taken.
722 * - outside a lamp the extended view is turned on or off
724 void pressEvent(XButtonEvent *xev)
726 if( region_in( xev->window, xev->x, xev->y ) )
727 region_mouse_click( xev->window, xev->x, xev->y, xev->button );
730 /* pointer motion
731 * - draws a lamp in an active state if the pointer passes above it
733 void motionEvent( XMotionEvent *xev )
735 region_mouse_motion( xev->window, xev->x, xev->y );
738 void exposeEvent( XExposeEvent *xev )
740 repaint( xev->window, xev->x, xev->y, xev->width, xev->height );
743 void alignInfoPanel()
745 /* get the position of the main win */
746 int win_x, win_y, screen_w, screen_h, panel_x, panel_y;
747 getWindowPosition( Win[activeWin], &win_x, &win_y );
748 getWindowDimension( Root, &screen_w, &screen_h );
749 /* find a suitable position for the info panel */
750 if( win_x - InfoWinDim.w > 0 )
751 panel_x = win_x - InfoWinDim.w;
752 else
753 panel_x = win_x + MainWinDim.w;
754 panel_y = win_y;
755 /* move the panel */
756 XMoveWindow( dpy, Win[2], panel_x, panel_y );
759 void mouseInLamp( int id )
761 drawLamp( id, ACTIVE );
762 for( int i=0; i < 3; i++ )
763 repaint( Win[activeWin], LampsRect[i].pos.x, LampsRect[i].pos.y, LampsRect[i].dim.w, LampsRect[i].dim.h );
766 void mouseOutLamp( int id )
768 drawLamp( id, INACTIVE );
769 for( int i=0; i < 3; i++ )
770 repaint( Win[activeWin], LampsRect[i].pos.x, LampsRect[i].pos.y, LampsRect[i].dim.w, LampsRect[i].dim.h );
773 void mouseClickLamp( int id, unsigned int button )
775 pressLamp( id, button );
776 update();
779 inline void drawInfoSwitch( int active )
781 int pixmap_index = (infoPanelActive ? 2:0) + active;
782 int offset_x = pixmap_index * InfoSWRect.dim.w;
783 XCopyArea( dpy, infoSWPixmap, disp, WinGC, offset_x, 0, InfoSWRect.dim.w, InfoSWRect.dim.h, InfoSWRect.pos.x, InfoSWRect.pos.y );
784 repaint( Win[activeWin], InfoSWRect.pos.x, InfoSWRect.pos.y, InfoSWRect.dim.w, InfoSWRect.dim.h );
787 void mouseInInfoSw( int id )
789 drawInfoSwitch(ACTIVE);
792 void mouseOutInfoSw( int id )
794 drawInfoSwitch(INACTIVE);
797 void mouseClickInfoSw( int id, unsigned int button )
799 if( !infoPanelActive )
801 alignInfoPanel();
802 XMapWindow( dpy, Win[2] );
803 } else
804 XUnmapWindow( dpy, Win[2] );
805 infoPanelActive = !infoPanelActive;
806 mouseInInfoSw( ID_SWITCH_INFO );
807 fullRepaint();
810 inline void drawLampsSwitch( int active )
812 int pixmap_index = (lampsActive ? 2:0) + active;
813 int offset_x = pixmap_index * LampsSWRect.dim.w;
814 XCopyArea( dpy, lampsSWPixmap, disp, WinGC, offset_x, 0, LampsSWRect.dim.w, LampsSWRect.dim.w, LampsSWRect.pos.x, LampsSWRect.pos.y );
815 repaint( Win[activeWin], LampsSWRect.pos.x, LampsSWRect.pos.y, LampsSWRect.dim.w, LampsSWRect.dim.h );
818 void mouseInLampsSw( int id )
820 drawLampsSwitch(ACTIVE);
823 void mouseOutLampsSw( int id )
825 drawLampsSwitch(INACTIVE);
828 void mouseClickLampsSw( int id, unsigned int button )
830 activateLamps( !lampsActive );
831 mouseInLampsSw( ID_SWITCH_LAMPS );
834 void activateLamps( bool active )
836 if( active )
838 drawLamp( 0, INACTIVE );
839 drawLamp( 1, INACTIVE );
840 drawLamp( 2, INACTIVE );
841 region_enable( Win[activeWin], ID_LAMP_GREEN );
842 region_enable( Win[activeWin], ID_LAMP_YELLOW );
843 region_enable( Win[activeWin], ID_LAMP_RED );
844 } else {
845 for( int i=0; i < 3; i++ )
846 blankMainWin( LampsRect[i].pos.x, LampsRect[i].pos.y, LampsRect[i].dim.w, LampsRect[i].dim.h );
847 region_disable( Win[activeWin], ID_LAMP_GREEN );
848 region_disable( Win[activeWin], ID_LAMP_YELLOW );
849 region_disable( Win[activeWin], ID_LAMP_RED );
851 lampsActive = active;
852 fullRepaint();
855 void drawSwitches()
857 drawInfoSwitch( INACTIVE );
858 drawLampsSwitch( INACTIVE );
861 void mouseInDevice( int id )
863 drawDevice(ACTIVE);
864 repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
867 void mouseOutDevice( int id )
869 drawDevice(INACTIVE);
870 repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
873 void mouseClickDevice( int id, unsigned int button )
875 selectNextDevice();
876 mouseInDevice( ID_DEVICE );
880 void drawDevice( int active )
882 char *color = active == ACTIVE ? DeviceColorHigh : DeviceColorLow;
883 drawText( devices[selected_device], disp, DeviceRect.pos.x, DeviceRect.pos.y, color );
886 void mouseInStatusSw( int id )
888 /* drawStatusSw( ACTIVE ); */
891 void mouseOutStatusSw( int id )
893 /* drawStatusSw( INACTIVE ); */
896 void mouseClickStatusSw( int id, unsigned int button )
898 if(button == 2)
899 pressStatusSw();
902 /* void drawStatusSw( int active ) */
904 void getWindowPosition( Window win, int *x, int *y )
906 XWindowAttributes winAttr;
907 Window dummy;
909 XGetWindowAttributes( dpy, win, &winAttr );
910 XTranslateCoordinates( dpy, win, winAttr.root,
911 -winAttr.border_width, -winAttr.border_width,
912 x, y, &dummy );
915 void getWindowDimension( Window win, int *w, int *h )
917 XWindowAttributes winAttr;
918 XGetWindowAttributes( dpy, win, &winAttr );
919 *w = winAttr.width;
920 *h = winAttr.height;
922 void repaint( Window win, int x, int y, int w, int h )
924 //bad code start
925 Pixmap src;
926 if( win == Win[activeWin] )
927 src = disp;
928 else if( win == Win[2] )
929 src = disp_info;
930 else {
931 syslog( LOG_DEBUG, "Oops! Unknown window given to repaint\n" );
932 return;
934 //bade code end
936 XCopyArea( dpy, src, win, WinGC, x, y, w, h, x, y );
937 XFlush(dpy);
940 void fullRepaint()
942 repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
943 if( infoPanelActive )
944 repaint( Win[2], 0, 0, InfoWinDim.w, InfoWinDim.h );
947 bool timeToUpdate()
949 static int ticker = 0;
950 if( ticker++ > UPDATE_INTERVAL )
952 ticker = 0;
953 return true;
955 return false;
958 /* get ISDN device status and update windows as needed */
959 void update()
961 isdnStatus stat;
962 getStatus( devices[selected_device], &stat );
963 if( memcmp(&curStatus, &stat, sizeof(stat)) != 0 )
965 memcpy( &curStatus, &stat, sizeof(stat) );
966 setStatusPixmap();
967 // drawDevice();
968 repaint( Win[activeWin], 0, 0, MainWinDim.w, MainWinDim.h );
970 updateInfoPanel();
971 repaint( Win[2], 0, 0, InfoWinDim.w, InfoWinDim.h );
974 /* set the appropriate pixmap on the main window */
975 void setStatusPixmap()
977 Pixmap statusPixmap, directionPixmap;
979 if( curStatus.usage > ISDN_USAGE_NONE && curStatus.usage <= ISDN_USAGE_FAX )
981 statusPixmap = statusPixmaps[curStatus.usage];
982 switch( curStatus.mpppMode )
984 case slave : directionPixmap = slavePixmap; break;
985 case master : if( curStatus.bundled == true ) { directionPixmap = bundledPixmap; break; }
986 if( is_slave_pending() ) { directionPixmap = bundlingPixmap; break; }
987 case none : directionPixmap = curStatus.direction == INCOMING ? incomingPixmap : outgoingPixmap; break;
988 default : syslog( LOG_DEBUG, "Ooops! curStatus.direction has an invalid value\n" ); directionPixmap = 0;
991 else {
992 switch( curStatus.usage )
994 case STAT_OFF : statusPixmap = offPixmap; break;
995 case ISDN_USAGE_NONE: statusPixmap = statusPixmaps[ISDN_USAGE_NONE]; break;
996 case STAT_DISABLED : statusPixmap = disabledPixmap; break;
997 case STAT_DIALING : statusPixmap = dialingPixmap; break;
998 case STAT_UNKNOWN : statusPixmap = unknownPixmap; break;
999 default : syslog( LOG_DEBUG, "Ooops! curStatus.usage has an invalid value\n" ); statusPixmap = 0;
1001 directionPixmap = 0;
1003 if( statusPixmap != 0 )
1004 XCopyArea(dpy, statusPixmap, disp, WinGC, StatusPixmapRect.pos.x, StatusPixmapRect.pos.y, StatusPixmapRect.dim.w, StatusPixmapRect.dim.h, StatusPixmapRect.pos.x, StatusPixmapRect.pos.y);
1005 if( directionPixmap != 0 )
1006 XCopyArea(dpy, directionPixmap, disp, WinGC, DirectionPixmapRect.pos.x, DirectionPixmapRect.pos.y, DirectionPixmapRect.dim.w, DirectionPixmapRect.dim.h, DirectionPixmapRect.pos.x, DirectionPixmapRect.pos.y);
1009 /* update the info panel */
1010 void updateInfoPanel()
1012 XSetForeground( dpy, WinGC, getColor(WindowBackgroundColor) );
1013 XFillRectangle( dpy, disp_info, WinGC, 0, 0, InfoWinDim.w, InfoWinDim.h );
1014 char line[100];
1015 if( (curStatus.usage > ISDN_USAGE_NONE && curStatus.usage <= ISDN_USAGE_FAX) || curStatus.usage == STAT_DIALING )
1017 sprintf( line, "peer phone: %s", curStatus.peerPhone );
1018 drawText( line, disp_info, 5, 5 );
1020 if( (curStatus.usage == ISDN_USAGE_NET) && (curStatus.mpppMode != slave) )
1022 int a, b, c, d;
1023 getLocalIP( &a, &b, &c, &d );
1024 sprintf( line, "local ip : %d.%d.%d.%d", a, b, c, d );
1025 drawText( line, disp_info, 5, 20 );
1026 getRemoteIP( &a, &b, &c, &d );
1027 sprintf( line, "remote ip: %d.%d.%d.%d", a, b, c, d );
1028 drawText( line, disp_info, 5, 35 );
1030 else if( curStatus.usage == STAT_OFF )
1031 drawText( "dialing disabled", disp_info, 5, 5 );
1032 else if( curStatus.usage == STAT_DISABLED )
1033 drawText( "device disabled", disp_info, 5, 5 );
1034 else if( curStatus.usage == ISDN_USAGE_NONE )
1036 drawText( "not connected", disp_info, 5, 5 );
1037 sprintf( line, "action: %s", scriptmodestrings[scriptmode] );
1038 drawText( line, disp_info, 5, 20 );
1040 switch( curStatus.mpppMode )
1042 case none : sprintf( line, "bundling: none" ); break;
1043 case master : sprintf( line, "bundling: master of %s", curStatus.mpppPartner ); break;
1044 case slave : sprintf( line, "bundling: slave of %s", curStatus.mpppPartner ); break;
1046 drawText( line, disp_info, 5, 50 );
1049 void blankMainWin( int x, int y, int w, int h )
1051 XCopyArea(dpy, coverPixmap, disp, WinGC, x, y, w, h, x, y);
1054 unsigned long getColor( const char *colorname )
1056 XColor color;
1057 XWindowAttributes winattr;
1058 XGetWindowAttributes(dpy, Root, &winattr);
1059 color.pixel=0;
1060 XParseColor(dpy, winattr.colormap, colorname, &color);
1061 color.flags=DoRed | DoGreen | DoBlue;
1062 XAllocColor(dpy, winattr.colormap, &color);
1063 return color.pixel;
1066 void createPixmap(char *data[], Pixmap *image, Pixmap *mask )
1068 XpmAttributes pixatt;
1070 pixatt.exactColors=false;
1071 pixatt.closeness=40000;
1072 pixatt.valuemask=XpmExactColors | XpmCloseness | XpmSize;
1073 XpmCreatePixmapFromData(dpy, Root, data, image, mask, &pixatt);
1076 void loadLeds( char *data[], Pixmap *image, const char *led_color, const char *back_color)
1078 XpmAttributes pixatt;
1079 unsigned long color[4];
1081 color[0] = mixColor(led_color, 0, back_color, 100);
1082 color[1] = mixColor(led_color, 100, back_color, 0);
1083 color[2] = mixColor(led_color, 60, back_color, 40);
1084 color[3] = mixColor(led_color, 25, back_color, 75);
1086 XpmColorSymbol xpmcsym[4]={{"led_color_back", NULL, color[0] },
1087 {"led_color_high", NULL, color[1]},
1088 {"led_color_med", NULL, color[2]},
1089 {"led_color_low", NULL, color[3]}};
1092 pixatt.numsymbols = 4;
1093 pixatt.colorsymbols = xpmcsym;
1094 pixatt.exactColors = false;
1095 pixatt.closeness = 40000;
1096 pixatt.valuemask = XpmColorSymbols | XpmExactColors | XpmCloseness | XpmSize;
1097 XpmCreatePixmapFromData(dpy, Root, data, image, NULL, &pixatt);
1100 unsigned long mixColor( const char *colorname1, int prop1, const char *colorname2, int prop2 )
1102 XColor color, color1, color2;
1103 XWindowAttributes winattr;
1104 XGetWindowAttributes(dpy, Root, &winattr);
1105 XParseColor(dpy, winattr.colormap, colorname1, &color1);
1106 XParseColor(dpy, winattr.colormap, colorname2, &color2);
1107 color.pixel=0;
1108 color.red=(color1.red*prop1+color2.red*prop2)/(prop1+prop2);
1109 color.green=(color1.green*prop1+color2.green*prop2)/(prop1+prop2);
1110 color.blue=(color1.blue*prop1+color2.blue*prop2)/(prop1+prop2);
1111 color.flags=DoRed | DoGreen | DoBlue;
1112 XAllocColor(dpy, winattr.colormap, &color);
1113 return color.pixel;
1116 /* draws text on dst using the led symbols from the leds pixmap */
1117 void leds_drawText( char *text, Pixmap dst, int x, int y, const char *color )
1119 Pixmap leds_pixmap;
1120 loadLeds( leds_xpm, &leds_pixmap, color, WindowBackgroundColor );
1122 x -= 3;
1123 char *led_ptr;
1124 while( *text != 0 )
1126 led_ptr = strchr( led_text, tolower(*text) );
1127 if( led_ptr == NULL )
1129 /*syslog( LOG_DEBUG, "Oops! Internal bug in drawText: No led symbol for char %c\n", *text );*/
1130 led_ptr = strchr( led_text, '?' );
1132 XCopyArea( dpy, leds_pixmap, dst, WinGC, (led_ptr-led_text)*LedDim.w, 0, LedDim.w, LedDim.h, x, y );
1133 x += LedDim.w;
1134 text++;
1136 XFreePixmap( dpy, leds_pixmap );
1139 /* draws text on dst using the X-Font from textFont */
1140 void font_drawText( char *text, Pixmap dst, int x, int y, const char *color )
1142 XSetForeground( dpy, WinGC, getColor(color) );
1143 XDrawImageString( dpy, dst, WinGC, x, y+textFont->ascent/2, text, strlen(text) );
1146 void drawText( char *text, Pixmap dst, int x, int y, const char *color )
1148 if( textFont == NULL )
1149 leds_drawText( text, dst, x, y, color );
1150 else
1151 font_drawText( text, dst, x, y, color );
1154 /* draws the lamp in the specified state */
1155 void drawLamp( int lamp, int active )
1157 int disp_x, disp_y, lamp_x=0;
1159 disp_x = LampsRect[lamp].pos.x;
1160 disp_y = LampsRect[lamp].pos.y;
1162 /* find the offset of the lamp pixmap in the pixmap of all lamps */
1163 for( int i=0; i < lamp; i++ )
1164 lamp_x += LampsRect[i].dim.w*2;
1165 lamp_x += active*LampsRect[lamp].dim.w;
1167 XCopyArea( dpy, lampsPixmap, disp, WinGC, lamp_x, 0, LampsRect[lamp].dim.w, LampsRect[lamp].dim.h, disp_x, disp_y );
1170 void isdnInitDefaultDialmode()
1172 seteuid( rootUID );
1173 setegid( rootGID );
1175 isdn_net_ioctl_cfg cfg;
1176 strcpy( cfg.name, devices[selected_device] );
1177 if( isdn_ioctl( IIOCNETGCF, &cfg, NULL ) != -1 )
1178 dialmode = cfg.dialmode;
1179 else
1180 dialmode = ISDN_NET_DM_AUTO; /* for the sake of cleanness, we'll get an error msg soon anyway */
1181 if( dialmode == ISDN_NET_DM_OFF )
1182 dialmode = ISDN_NET_DM_AUTO; /* use auto as default dialmode if device disabled */
1184 seteuid( getuid() );
1185 setegid( getgid() );
1188 int isdn_ioctl( int func, void *arg, const char *errmsg, const char *filename )
1190 int fd = fd = open( filename, O_RDONLY );
1191 if( fd == -1 )
1193 if( errmsg != NULL )
1194 syslog( LOG_NOTICE, "Couldn't open %s : %m\n", filename );
1195 return -1;
1198 int res = ioctl( fd, func, arg );
1199 if( res == -1 && errmsg != NULL )
1200 syslog( LOG_NOTICE, "%s : %m\n", errmsg );
1202 close(fd);
1204 return res;
1207 inline void isdn_dial()
1209 if( !usescripts )
1210 isdn_ioctl( IIOCNETDIL, devices[selected_device], "Couldn't dial" );
1211 else
1214 int handle;
1215 char command[MAX_ARG_LEN];
1217 strcpy(command, scriptpath);
1218 strcat(command, "/");
1219 strcat(command, SCRIPT_UP);
1220 if ((handle = open(command, O_RDONLY)) == -1)
1221 syslog( LOG_NOTICE, "Couldn't open %s : %m\n", SCRIPT_UP );
1222 else {
1223 close(handle);
1224 sprintf(command, "%s/%s %s %d 2>&1 | logger -t wmisdn.sh &", scriptpath, SCRIPT_UP, devices[selected_device], scriptmode);
1225 system(command);
1228 update();
1231 inline void isdn_hangup()
1233 if( !usescripts )
1234 isdn_ioctl( IIOCNETHUP, devices[selected_device], "Couldn't hang up" );
1235 else
1237 int handle;
1238 char command[MAX_ARG_LEN];
1240 strcpy(command, scriptpath);
1241 strcat(command, "/");
1242 strcat(command, SCRIPT_DOWN);
1244 if ((handle = open(command, O_RDONLY)) == -1)
1245 syslog( LOG_NOTICE, "Couldn't open %s : %m\n", SCRIPT_DOWN );
1246 else {
1247 close(handle);
1248 sprintf(command, "%s/%s %s %d 2>&1 | logger -t wmisdn.sh &", scriptpath, SCRIPT_DOWN, devices[selected_device], scriptmode);
1249 system(command);
1252 update();
1255 inline void isdn_enable()
1257 isdn_net_ioctl_cfg cfg;
1258 strcpy( cfg.name, devices[selected_device] );
1259 if( isdn_ioctl( IIOCNETGCF, &cfg, "Error enabling dialing. Couldn't get dev cfg" ) != -1 )
1261 cfg.dialmode = dialmode;
1262 isdn_ioctl( IIOCNETSCF, &cfg, "Error enabling dialing. Couldn't set dev cfg" );
1266 inline void isdn_disable()
1268 isdn_net_ioctl_cfg cfg;
1269 strcpy( cfg.name, devices[selected_device] );
1270 if( isdn_ioctl( IIOCNETGCF, &cfg, "Error disabling dialing. Couldn't get dev cfg" ) != -1 )
1272 cfg.dialmode = ISDN_NET_DM_OFF;
1273 isdn_ioctl( IIOCNETSCF, &cfg, "Error disabling dialing. Couldn't set dev cfg" );
1277 inline void isdn_dial_slave( char *master )
1279 isdn_ioctl( IIOCNETALN, master, "Couldn't fire up slave" );
1282 inline void isdn_hangup_slave( char *master )
1284 isdn_ioctl( IIOCNETDLN, master, "Couldn't hang up slave" );
1287 inline void set_slave_pending()
1289 slave_pending = devices[selected_device];
1292 inline void clear_slave_pending()
1294 slave_pending = NULL;
1297 inline bool is_slave_pending()
1299 return slave_pending != NULL;
1302 inline void manage_slave()
1304 if( is_slave_pending() )
1306 if( curStatus.usage == ISDN_USAGE_NET )
1308 isdn_dial_slave(slave_pending);
1309 clear_slave_pending();
1311 if( curStatus.usage == ISDN_USAGE_NONE )
1312 clear_slave_pending();
1316 /* react upon a lamp press
1317 * - green opens a connection and sets the device in dial_auto mode
1318 * - yellow ends the connection and sets the device in dial_auto mode
1319 * - red ends the connection and sets the device in dial_off mode
1322 inline void _pressGreenLamp( int button )
1324 /* middle button - just change the script mode */
1325 if( button == 2 )
1327 advanceScriptMode();
1328 return;
1330 /* online request of slave - add a channel to the master */
1331 if( curStatus.mpppMode == slave )
1332 isdn_dial_slave( curStatus.mpppPartner );
1333 /* online request of master or non-bundled device */
1334 else {
1335 /* additional mppp-link requested - add a slave channel to the master (wait until master online) */
1336 if( (button == 3) && (curStatus.mpppMode == master) )
1337 set_slave_pending();
1338 /* if device is dialing or online - ignore button */
1339 if( curStatus.usage == STAT_DIALING || curStatus.usage == ISDN_USAGE_NET )
1340 return;
1341 if( curStatus.usage == STAT_OFF )
1342 isdn_enable();
1343 isdn_dial();
1347 inline void _pressYellowLamp( int button )
1349 if( curStatus.usage == ISDN_USAGE_NONE )
1350 return;
1351 if( curStatus.usage == STAT_OFF )
1352 isdn_enable();
1353 else
1355 if( (button == 3) || (button == 1) && (curStatus.mpppMode == master) )
1356 isdn_hangup_slave( devices[selected_device] );
1357 if( button == 1 )
1359 if( curStatus.mpppMode == slave )
1360 isdn_hangup_slave( curStatus.mpppPartner );
1361 else
1362 isdn_hangup();
1367 inline void _pressRedLamp( int button )
1369 if( (curStatus.usage == STAT_OFF) || (button != 1) )
1370 return;
1371 _pressYellowLamp( button );
1372 isdn_disable();
1375 void pressLamp( int lamp_id, int button )
1377 seteuid( rootUID );
1378 setegid( rootGID );
1379 switch( lamp_id )
1381 case ID_LAMP_GREEN : _pressGreenLamp( button );break;
1382 case ID_LAMP_YELLOW : _pressYellowLamp( button ); break;
1383 case ID_LAMP_RED : _pressRedLamp( button ); break;
1385 seteuid( getuid() );
1386 setegid( getgid() );
1389 /* activated when user clicks the status pixmap with the right button - switch online<->offline */
1390 void pressStatusSw()
1392 seteuid( rootUID );
1393 setegid( rootGID );
1395 if( curStatus.usage == ISDN_USAGE_NONE )
1396 _pressGreenLamp(1);
1397 else if(curStatus.usage == ISDN_USAGE_NET )
1398 _pressYellowLamp(1);
1400 seteuid( getuid() );
1401 setegid( getgid() );
1405 /* Get the local/remote IP addresses of the devices[selected_device] */
1407 void getLocalIP( int *a, int *b, int *c, int *d )
1409 struct ifreq ifr;
1410 int fd = socket( AF_INET, SOCK_DGRAM, 0 );
1412 strcpy( ifr.ifr_ifrn.ifrn_name, devices[selected_device] );
1413 ifr.ifr_ifru.ifru_addr.sa_family = AF_INET;
1414 int res = ioctl(fd, SIOCGIFADDR, &ifr);
1415 close(fd);
1416 translateIP( &(ifr.ifr_ifru.ifru_addr), a, b, c, d );
1418 if( res != 0 )
1419 syslog( LOG_NOTICE, "Oops! Couldn't get local IP of device %s. ioctl() call failed : %m\n", devices[selected_device] );
1422 void getRemoteIP( int *a, int *b, int *c, int *d )
1424 struct ifreq ifr;
1425 int fd = socket( AF_INET, SOCK_DGRAM, 0 );
1427 strcpy( ifr.ifr_ifrn.ifrn_name, devices[selected_device] );
1428 ifr.ifr_ifru.ifru_addr.sa_family = AF_INET;
1429 int res = ioctl( fd, SIOCGIFDSTADDR, &ifr );
1430 close(fd);
1431 translateIP( &(ifr.ifr_ifru.ifru_addr), a, b, c, d );
1433 if( res != 0 )
1434 syslog( LOG_NOTICE, "Oops! Couldn't get remote IP of device %s. ioctl() call failed : %m\n", devices[selected_device]);
1437 /* extract the ip address from the addr struct asuming that it is a valid INET sockaddr */
1438 inline void translateIP( struct sockaddr *addr, int *a, int *b, int *c, int *d )
1440 struct sockaddr_in* inet_addr = (sockaddr_in *)addr;
1441 unsigned int ip = inet_addr->sin_addr.s_addr;
1442 *d = (ip >> 24) & 0xFF;
1443 *c = (ip >> 16) & 0xFF;
1444 *b = (ip >> 8 ) & 0xFF;
1445 *a = ip & 0xFF;
1448 /* extract the data from the 'key'-line of /dev/isdninfo for all 16 B-Channels */
1449 bool extractIsdnInfoData( const char *all_data, const char *key, char buffer[ISDN_MAX_CHANNELS][100] )
1451 char temp[100]; /* buffer the key string */
1452 char *ptr;
1454 ptr = strstr( all_data, key );
1455 if( ptr == NULL )
1457 syslog( LOG_NOTICE, "Error getting status info. /dev/isdninfo doesn't contain a '%s' line\n", key );
1458 return false;
1460 sscanf( ptr, "%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
1461 temp,
1462 buffer[0], buffer[1], buffer[2], buffer[3],
1463 buffer[4], buffer[5], buffer[6], buffer[7],
1464 buffer[8], buffer[9], buffer[10], buffer[11],
1465 buffer[12], buffer[13], buffer[14], buffer[15] );
1467 return true;
1470 bool getPeerPhone( char *ippp, char *phone )
1472 isdn_net_ioctl_phone ippp_phone;
1473 int res;
1475 strcpy( ippp_phone.name, ippp );
1476 res = isdn_ioctl( IIOCNETGPN, &ippp_phone, NULL, "/dev/isdninfo" );
1477 if( res < 0 )
1479 if( errno != ENOTCONN ) /* device not connected - no real error */
1480 syslog( LOG_NOTICE, "Error getting phone number for device %s: %m", ippp );
1481 return false;
1483 strcpy( phone, ippp_phone.phone );
1484 return true;
1487 bool findBChannel( char *phone, char all_phones[ISDN_MAX_CHANNELS][100], int &channel )
1489 for( int i=0; i < ISDN_MAX_CHANNELS; i++ )
1490 if( strcmp( all_phones[i], phone ) == 0 )
1492 channel = i;
1493 return true;
1495 syslog( LOG_NOTICE, "Hmm!!?? That's strange! Device phone number %s couldn't be found in /dev/isdninfo", phone );
1496 return false;
1499 void getMPPPSettings( isdn_net_ioctl_cfg *cfg, isdnStatus *stat )
1501 stat->mpppMode = none;
1502 if( strlen(cfg->master) != 0 )
1504 stat->mpppMode = slave;
1505 strcpy( stat->mpppPartner, cfg->master );
1507 if( strlen(cfg->slave) != 0 )
1509 stat->mpppMode = master;
1510 strcpy( stat->mpppPartner, cfg->slave );
1514 /* get the status of the ippp device:
1516 * - isOff if dialing is disabled
1517 * - isOffline if dialing is enabled but no connection is established
1518 * - isOnline if device has established a connection
1519 * - isDialing if device is dialing the remote but no connection is established
1520 * - isUnknown if no stat info available
1522 void getStatus( char *device, isdnStatus *stat )
1524 isdn_net_ioctl_cfg cfg;
1525 int fd, len, res;
1526 char buf[10000];
1527 static int warning_count=0;
1528 int channel, channel_usage;
1529 char channel_info[ISDN_MAX_CHANNELS][100];
1532 /* get ippp device config */
1533 seteuid( rootUID );
1534 setegid( rootGID );
1535 strcpy( cfg.name, device );
1536 res = isdn_ioctl( IIOCNETGCF, &cfg, warning_count < STATUS_WARNING_SAT ? "Error getting status info. Couldn't get device cfg" : (char *)NULL );
1537 seteuid( getuid() );
1538 setegid( getgid() );
1540 stat->usage = STAT_UNKNOWN;
1541 stat->direction = INCOMING;
1543 if( res == -1 )
1545 warning_count++;
1546 return;
1548 warning_count = 0;
1549 if( cfg.dialmode == ISDN_NET_DM_OFF )
1550 stat->usage = STAT_OFF;
1551 else
1552 stat->usage = ISDN_USAGE_NONE;
1554 stat->bundled = false;
1555 getMPPPSettings( &cfg, stat );
1557 /* read the device flags from /dev/isdninfo */
1558 fd = open( "/dev/isdninfo", O_RDONLY|O_NDELAY );
1559 if( fd == -1 )
1561 syslog( LOG_NOTICE, "Error getting status info. Couldn't open /dev/isdninfo : %m\n" );
1562 return;
1564 len = read( fd, buf, sizeof(buf)-1 );
1565 close(fd);
1566 if( len == -1 )
1568 syslog( LOG_NOTICE, "Error getting status info. Couldn't read from /dev/isdninfo : %m\n" );
1569 return;
1571 buf[len] = 0; /* terminate the string */
1573 if( !extractIsdnInfoData( buf, "phone:", channel_info ) )
1574 return;
1575 if( !getPeerPhone( device, stat->peerPhone ) )
1576 return;
1577 if( !findBChannel( stat->peerPhone, channel_info, channel ) )
1578 return;
1579 if( !extractIsdnInfoData( buf, "usage:", channel_info ) )
1580 return;
1582 channel_usage = atoi(channel_info[channel]);
1583 if( (channel_usage & ISDN_USAGE_DISABLED) != 0 )
1584 stat->usage = STAT_DISABLED;
1585 else
1586 stat->usage = channel_usage & ISDN_USAGE_MASK;
1587 stat->direction = (channel_usage & ISDN_USAGE_OUTGOING) == 0 ? INCOMING : OUTGOING;
1589 /* check if device is still dialing or already online */
1590 if( stat->usage == ISDN_USAGE_NET )
1593 if( !extractIsdnInfoData( buf, "flags:", channel_info ) )
1594 return;
1596 if( ((atoi(channel_info[0]) >> channel) & 1) == 0 )
1597 stat->usage = STAT_DIALING;
1599 /* check for channel bundling */
1600 if( stat->mpppMode == master )
1602 isdnStatus slaveStatus;
1603 getStatus( stat->mpppPartner, &slaveStatus );
1604 if( (stat->usage == slaveStatus.usage) && (stat->direction == slaveStatus.direction) &&
1605 (strcmp(stat->peerPhone,slaveStatus.peerPhone)==0) )
1606 stat->bundled = true;