isdn4k-utils/xmonisdn/Net.c

768 lines
21 KiB
C

#include <X11/IntrinsicP.h> /* for toolkit stuff */
#include <X11/StringDefs.h> /* for useful atom names */
#include <X11/cursorfont.h> /* for cursor constants */
#include <X11/Xosdefs.h> /* for X_NOT_POSIX def */
#include <pwd.h> /* for getting username */
#include <sys/stat.h> /* for stat() ** needs types.h ***/
#include <unistd.h>
#include <stdio.h> /* for printing error messages */
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <linux/isdn.h>
#ifndef X_NOT_POSIX
#ifdef _POSIX_SOURCE
# include <sys/wait.h>
#else
#define _POSIX_SOURCE
# include <sys/wait.h>
#undef _POSIX_SOURCE
#endif
# define waitCode(w) WEXITSTATUS(w)
# define waitSig(w) WIFSIGNALED(w)
typedef int waitType;
# define INTWAITTYPE
#else /* ! X_NOT_POSIX */
#ifdef SYSV
# define waitCode(w) (((w) >> 8) & 0x7f)
# define waitSig(w) ((w) & 0xff)
typedef int waitType;
# define INTWAITTYPE
#else
# include <sys/wait.h>
# define waitCode(w) ((w).w_T.w_Retcode)
# define waitSig(w) ((w).w_T.w_Termsig)
typedef union wait waitType;
#endif /* SYSV else */
#endif /* ! X_NOT_POSIX else */
#include <X11/bitmaps/netactive>
#include <X11/bitmaps/netinactive>
#include <X11/bitmaps/netwaiting>
#include <X11/bitmaps/netactiveout>
#include <X11/bitmaps/netstart>
#include <X11/bitmaps/netstop>
#include <X11/Xaw/XawInit.h>
#include "NetP.h"
#include <X11/Xmu/Drawing.h>
#include <X11/extensions/shape.h>
/* Only allow calling scripts when setuid root if the -r option is given */
extern int allow_setuid;
/*
* The default user interface is to have the netstat turn itself off whenever
* the user presses a button in it. Expert users might want to make this
* happen on EnterWindow. It might be nice to provide support for some sort of
* exit callback so that you can do things like press q to quit.
*/
static char defaultTranslations[] =
"<ButtonPress>Button2: netup()\n\
<ButtonPress>Button3: netdown()";
static void Check(), NetUp(), NetDown();
static XtActionsRec actionsList[] = {
{ "check", Check },
{ "netup", NetUp },
{ "netdown",NetDown },
};
/* Initialization of defaults */
#define offset(field) XtOffsetOf(NetstatRec, netstat.field)
#define goffset(field) XtOffsetOf(WidgetRec, core.field)
static Dimension defDim = 48;
static Pixmap nopix = None;
static XtResource resources[] = {
{ XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
goffset (width), XtRDimension, (XtPointer)&defDim },
{ XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
goffset (height), XtRDimension, (XtPointer)&defDim },
{ XtNupdate, XtCInterval, XtRInt, sizeof (int),
offset (update), XtRString, "5" },
{ XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
offset (foreground_pixel), XtRString, XtDefaultForeground },
{ XtNfile, XtCFile, XtRString, sizeof (String),
offset (filename), XtRString, NULL },
{ XtNvolume, XtCVolume, XtRInt, sizeof(int),
offset (volume), XtRString, "33"},
{ XtNactivePixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
offset (active.bitmap), XtRString, "netactive" },
{ XtNactivePixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
offset (active.mask), XtRBitmap, (XtPointer) &nopix },
{ XtNactiveoutPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
offset (activeout.bitmap), XtRString, "netactiveout" },
{ XtNactiveoutPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
offset (activeout.mask), XtRBitmap, (XtPointer) &nopix },
{ XtNwaitingPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
offset (waiting.bitmap), XtRString, "netwaiting" },
{ XtNwaitingPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
offset (waiting.mask), XtRBitmap, (XtPointer) &nopix },
{ XtNinactivePixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
offset (inactive.bitmap), XtRString, "netinactive" },
{ XtNinactivePixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
offset (inactive.mask), XtRBitmap, (XtPointer) &nopix },
{ XtNstartPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
offset (start.bitmap), XtRString, "netstart" },
{ XtNstartPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
offset (start.mask), XtRBitmap, (XtPointer) &nopix },
{ XtNstopPixmap, XtCPixmap, XtRBitmap, sizeof(Pixmap),
offset (stop.bitmap), XtRString, "netstop" },
{ XtNstopPixmapMask, XtCPixmapMask, XtRBitmap, sizeof(Pixmap),
offset (stop.mask), XtRBitmap, (XtPointer) &nopix },
{ XtNflip, XtCFlip, XtRBoolean, sizeof(Boolean),
offset (flipit), XtRString, "true" },
{ XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof(Boolean),
offset (shapeit), XtRString, "false" },
};
#undef offset
#undef goffset
static void GetNetinfoFile(), CloseDown();
static void check_netstat(), redraw_netstat(), beep();
static void Initialize(), Realize(), Destroy(), Redisplay();
static Boolean SetValues();
static int parse_info();
NetstatClassRec netstatClassRec = {
{ /* core fields */
/* superclass */ (WidgetClass) &simpleClassRec,
/* class_name */ "Netstat",
/* widget_size */ sizeof(NetstatRec),
/* class_initialize */ XawInitializeWidgetSet,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ actionsList,
/* num_actions */ XtNumber(actionsList),
/* resources */ resources,
/* resource_count */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ NULL,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ XtInheritQueryGeometry,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* simple fields */
/* change_sensitive */ XtInheritChangeSensitive
},
{ /* netstat fields */
/* ignore */ 0
}
};
WidgetClass netstatWidgetClass = (WidgetClass) &netstatClassRec;
static FILE *isdninfo;
static int updownwait = 0;
/*
* widget initialization
*/
static GC get_netstat_gc (w)
NetstatWidget w;
{
XtGCMask valuemask;
XGCValues xgcv;
valuemask = GCForeground | GCBackground | GCFunction | GCGraphicsExposures;
xgcv.foreground = w->netstat.foreground_pixel;
xgcv.background = w->core.background_pixel;
xgcv.function = GXcopy;
xgcv.graphics_exposures = False; /* this is Bool, not Boolean */
return (XtGetGC ((Widget) w, valuemask, &xgcv));
}
/* ARGSUSED */
static void Initialize (request, new, args, num_args)
Widget request, new;
ArgList args;
Cardinal *num_args;
{
NetstatWidget w = (NetstatWidget) new;
int shape_event_base, shape_error_base;
if (w->core.width <= 0) w->core.width = 1;
if (w->core.height <= 0) w->core.height = 1;
if (w->netstat.shapeit && !XShapeQueryExtension (XtDisplay (w),
&shape_event_base,
&shape_error_base))
w->netstat.shapeit = False;
w->netstat.shape_cache.mask = None;
w->netstat.gc = get_netstat_gc (w);
w->netstat.interval_id = (XtIntervalId) 0;
w->netstat.active.pixmap = None;
w->netstat.inactive.pixmap = None;
w->netstat.waiting.pixmap = None;
w->netstat.activeout.pixmap = None;
w->netstat.start.pixmap = None;
w->netstat.stop.pixmap = None;
w->netstat.state = 0;
if (!w->netstat.filename) GetNetinfoFile (w);
return;
}
/*
* action procedures
*/
/*
* paranoia_check - enhanced security.
*
* refuse execution, if cmd is NOT owned by
* root or writeable by group or world.
*
*/
/* ARGSUSED */
static int paranoia_check(cmd)
char *cmd;
{
#ifdef PARANOIA_CHECK
struct stat stbuf;
/* only check if setuid root */
if (geteuid() != 0 || getuid() == 0)
return 1;
/* don't allow any scripts if setuid root and not called with -r option */
if (!allow_setuid)
return 0;
if (stat(cmd, &stbuf))
/* stat failed, stay on the safe side */
return 0;
if (stbuf.st_uid != 0)
/* owner is not root */
return 0;
if (stbuf.st_mode & (S_IWGRP | S_IWOTH))
/* writable by group or world */
return 0;
#endif
return 1;
}
/* ARGSUSED */
static void NetUp (gw, event, params, nparams)
Widget gw;
XEvent *event;
String *params;
Cardinal *nparams;
{
NetstatWidget w = (NetstatWidget) gw;
if ((w->netstat.state <= 2) && (!updownwait)) {
w->netstat.state = 5;
updownwait = 150 / w->netstat.update;
if (updownwait < 2)
updownwait = 2;
redraw_netstat(w);
if (paranoia_check(NETUP_COMMAND))
system(NETUP_COMMAND);
}
return;
}
/* ARGSUSED */
static void NetDown (gw, event, params, nparams)
Widget gw;
XEvent *event;
String *params;
Cardinal *nparams;
{
NetstatWidget w = (NetstatWidget) gw;
if ((w->netstat.state > 1) && (w->netstat.state < 5) && (!updownwait)) {
w->netstat.state = 6;
redraw_netstat(w);
updownwait = 150 / w->netstat.update;
if (updownwait < 2)
updownwait = 2;
if (paranoia_check(NETDOWN_COMMAND))
system(NETDOWN_COMMAND);
}
return;
}
/* ARGSUSED */
static void Check (gw, event, params, nparams)
Widget gw;
XEvent *event;
String *params;
Cardinal *nparams;
{
NetstatWidget w = (NetstatWidget) gw;
if (!updownwait) {
w->netstat.state = 0;
fclose(isdninfo);
check_netstat (w);
}
return;
}
/* ARGSUSED */
static void clock_tic (client_data, id)
XtPointer client_data;
XtIntervalId *id;
{
NetstatWidget w = (NetstatWidget) client_data;
check_netstat (w);
/*
* reset the timer
*/
w->netstat.interval_id =
XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
w->netstat.update * 100, clock_tic, client_data);
return;
}
static Pixmap make_pixmap (dpy, w, bitmap, depth, flip, widthp, heightp)
Display *dpy;
NetstatWidget w;
Pixmap bitmap;
Boolean flip;
int depth;
int *widthp, *heightp;
{
Window root;
int x, y;
unsigned int width, height, bw, dep;
unsigned long fore, back;
if (!XGetGeometry (dpy, bitmap, &root, &x, &y, &width, &height, &bw, &dep))
return None;
*widthp = (int) width;
*heightp = (int) height;
if (flip) {
fore = w->core.background_pixel;
back = w->netstat.foreground_pixel;
} else {
fore = w->netstat.foreground_pixel;
back = w->core.background_pixel;
}
return XmuCreatePixmapFromBitmap (dpy, w->core.window, bitmap,
width, height, depth, fore, back);
}
static void Realize (gw, valuemaskp, attr)
Widget gw;
XtValueMask *valuemaskp;
XSetWindowAttributes *attr;
{
NetstatWidget w = (NetstatWidget) gw;
register Display *dpy = XtDisplay (w);
int depth = w->core.depth;
*valuemaskp |= (CWBitGravity | CWCursor);
attr->bit_gravity = ForgetGravity;
attr->cursor = XCreateFontCursor (dpy, XC_top_left_arrow);
(*netstatWidgetClass->core_class.superclass->core_class.realize)
(gw, valuemaskp, attr);
/*
* build up the pixmaps that we'll put into the image
*/
if (w->netstat.active.bitmap == None) {
w->netstat.active.bitmap =
XCreateBitmapFromData (dpy, w->core.window, (char *) netactive_bits,
netactive_width, netactive_height);
}
if (w->netstat.inactive.bitmap == None) {
w->netstat.inactive.bitmap =
XCreateBitmapFromData (dpy, w->core.window, (char *) netinactive_bits,
netinactive_width, netinactive_height);
}
if (w->netstat.waiting.bitmap == None) {
w->netstat.waiting.bitmap =
XCreateBitmapFromData (dpy, w->core.window, (char *) netwaiting_bits,
netwaiting_width, netwaiting_height);
}
if (w->netstat.activeout.bitmap == None) {
w->netstat.activeout.bitmap =
XCreateBitmapFromData (dpy, w->core.window, (char *) netactiveout_bits,
netactiveout_width, netactiveout_height);
}
if (w->netstat.start.bitmap == None) {
w->netstat.start.bitmap =
XCreateBitmapFromData (dpy, w->core.window, (char *) netstart_bits,
netstart_width, netstart_height);
}
if (w->netstat.stop.bitmap == None) {
w->netstat.stop.bitmap =
XCreateBitmapFromData (dpy, w->core.window, (char *) netstop_bits,
netstop_width, netstop_height);
}
w->netstat.inactive.pixmap = make_pixmap (dpy, w, w->netstat.inactive.bitmap,
depth, False,
&w->netstat.inactive.width,
&w->netstat.inactive.height);
w->netstat.active.pixmap = make_pixmap (dpy, w, w->netstat.active.bitmap,
depth, False,
&w->netstat.active.width,
&w->netstat.active.height);
w->netstat.waiting.pixmap = make_pixmap (dpy, w, w->netstat.waiting.bitmap,
depth, False,
&w->netstat.waiting.width,
&w->netstat.waiting.height);
w->netstat.activeout.pixmap = make_pixmap (dpy, w, w->netstat.activeout.bitmap,
depth, w->netstat.flipit,
&w->netstat.activeout.width,
&w->netstat.activeout.height);
w->netstat.start.pixmap = make_pixmap (dpy, w, w->netstat.start.bitmap,
depth, False,
&w->netstat.start.width,
&w->netstat.start.height);
w->netstat.stop.pixmap = make_pixmap (dpy, w, w->netstat.stop.bitmap,
depth, False,
&w->netstat.stop.width,
&w->netstat.stop.height);
if (w->netstat.inactive.mask == None || w->netstat.active.mask == None ||
w->netstat.waiting.mask == None || w->netstat.activeout.mask == None ||
w->netstat.start.mask == None || w->netstat.stop.mask == None)
w->netstat.shapeit = False;
w->netstat.interval_id =
XtAppAddTimeOut (XtWidgetToApplicationContext((Widget) w),
w->netstat.update * 100, clock_tic, (XtPointer) w);
w->netstat.shape_cache.mask = None;
check_netstat (w);
return;
}
static void Destroy (gw)
Widget gw;
{
NetstatWidget w = (NetstatWidget) gw;
Display *dpy = XtDisplay (gw);
XtFree (w->netstat.filename);
if (w->netstat.interval_id) XtRemoveTimeOut (w->netstat.interval_id);
XtReleaseGC(gw, w->netstat.gc);
#define freepix(p) if (p) XFreePixmap (dpy, p)
freepix (w->netstat.active.bitmap);
freepix (w->netstat.active.mask);
freepix (w->netstat.active.pixmap);
freepix (w->netstat.inactive.bitmap);
freepix (w->netstat.inactive.mask);
freepix (w->netstat.inactive.pixmap);
freepix (w->netstat.waiting.bitmap);
freepix (w->netstat.waiting.mask);
freepix (w->netstat.waiting.pixmap);
freepix (w->netstat.activeout.bitmap);
freepix (w->netstat.activeout.mask);
freepix (w->netstat.activeout.pixmap);
freepix (w->netstat.start.bitmap);
freepix (w->netstat.start.mask);
freepix (w->netstat.start.pixmap);
freepix (w->netstat.stop.bitmap);
freepix (w->netstat.stop.mask);
freepix (w->netstat.stop.pixmap);
freepix (w->netstat.shape_cache.mask);
#undef freepix
return;
}
static void Redisplay (gw, event, region)
Widget gw;
XEvent *event;
Region region;
{
NetstatWidget w = (NetstatWidget) gw;
check_netstat (w);
redraw_netstat(w);
}
static void check_netstat (w)
NetstatWidget w;
{
int newstate = 0;
struct timeval timeout;
fd_set fdset;
if (w->netstat.state >= 5) { /* network start or stop */
if (updownwait <= 0) {
fclose(isdninfo);
w->netstat.state = 0;
updownwait = 0;
} else updownwait--;
}
if (w->netstat.state == 0) { /* first invocation */
if (!w->netstat.filename) GetNetinfoFile();
if (!(isdninfo = fopen(w->netstat.filename, "r"))) {
fprintf(stderr, "xmonisdn: Can't open %s\n",w->netstat.filename);
CloseDown(w,-1);
}
}
FD_ZERO(&fdset);
FD_SET(fileno(isdninfo),&fdset);
timeout.tv_sec = 0;
timeout.tv_usec = 200;
switch (select(32,&fdset,(fd_set *)0,(fd_set *)0,&timeout)) {
case 0: /* nothing changed */
if (w->netstat.state == 0) {
fprintf(stderr, "xmonisdn: No info from isdninfo-file after initial poll\n");
CloseDown(w,-1);
}
return;
case 1: /* read new info */
newstate = parse_info();
break;
default:
fprintf(stderr,"xmonisdn: Error in select-statement\n");
CloseDown(w,-1);
}
if (newstate == w->netstat.state) return;
else {
if (((w->netstat.state == 4) || (newstate == 4)) &&
(w->netstat.state < 5) && (newstate < 5)) beep(w);
w->netstat.state = newstate;
updownwait = 0;
}
redraw_netstat(w);
}
static int parse_info()
{
char infoline[4096];
char temp[128];
char *infoptr;
register int i;
int num;
int newstate;
newstate = 1;
fgets(infoline, 4095, isdninfo); /* idmap */
fgets(infoline, 4095, isdninfo); /* chmap */
infoptr = infoline + 7;
for (i=0; i<ISDN_MAX_CHANNELS; i++) {
sscanf(infoptr,"%d",&num);
if (num != -1) newstate = 2;
sscanf(infoptr,"%s",temp);
infoptr = infoptr + strlen(temp) + 1;
}
fgets(infoline, 4095, isdninfo); /* drmap */
fgets(infoline, 4095, isdninfo); /* usage */
if (newstate >= 2) {
infoptr = infoline + 7;
for (i=0; i<ISDN_MAX_CHANNELS; i++) {
sscanf(infoptr,"%d",&num);
if ((num&ISDN_USAGE_MASK) == ISDN_USAGE_NET) {
if (num&ISDN_USAGE_OUTGOING)
newstate = 4;
else
if (newstate < 3)
newstate = 3;
}
sscanf(infoptr,"%s",temp);
infoptr = infoptr + strlen(temp) + 1;
}
}
fgets(infoline, 4095, isdninfo); /* flags */
fgets(infoline, 4095, isdninfo); /* phone */
return newstate;
}
static void GetNetinfoFile (w)
NetstatWidget w;
{
char *netinfo_file;
struct stat stbuf;
netinfo_file="/dev/isdn/isdninfo";
if (stat(netinfo_file, &stbuf)<0)
netinfo_file="/dev/isdninfo";
w->netstat.filename = (String) XtMalloc (strlen (netinfo_file) + 1);
strcpy (w->netstat.filename, netinfo_file);
return;
}
static void CloseDown (w, status)
NetstatWidget w;
int status;
{
Display *dpy = XtDisplay (w);
XtDestroyWidget ((Widget)w);
XCloseDisplay (dpy);
exit (status);
}
/* ARGSUSED */
static Boolean SetValues (gcurrent, grequest, gnew, args, num_args)
Widget gcurrent, grequest, gnew;
ArgList args;
Cardinal *num_args;
{
NetstatWidget current = (NetstatWidget) gcurrent;
NetstatWidget new = (NetstatWidget) gnew;
Boolean redisplay = FALSE;
if (current->netstat.update != new->netstat.update) {
if (current->netstat.interval_id)
XtRemoveTimeOut (current->netstat.interval_id);
new->netstat.interval_id =
XtAppAddTimeOut (XtWidgetToApplicationContext(gnew),
new->netstat.update * 100, clock_tic,
(XtPointer) gnew);
}
if (current->netstat.foreground_pixel != new->netstat.foreground_pixel ||
current->core.background_pixel != new->core.background_pixel) {
XtReleaseGC (gcurrent, current->netstat.gc);
new->netstat.gc = get_netstat_gc (new);
redisplay = TRUE;
}
return (redisplay);
}
/*
* drawing code
*/
static void redraw_netstat (w)
NetstatWidget w;
{
register Display *dpy = XtDisplay (w);
register Window win = XtWindow (w);
register int x, y;
GC gc = w->netstat.gc;
Pixel back = w->core.background_pixel;
struct _mbimage *im = 0;
/* center the picture in the window */
switch (w->netstat.state) {
case 0:
case 1:
im = &w->netstat.inactive;
break;
case 2:
im = &w->netstat.waiting;
break;
case 3:
im = &w->netstat.active;
break;
case 4:
im = &w->netstat.activeout;
if (w->netstat.flipit) back = w->netstat.foreground_pixel;
break;
case 5:
im = &w->netstat.start;
break;
case 6:
im = &w->netstat.stop;
break;
default:
fprintf(stderr,"xmonisdn: Error in redrawing -- wrong netstat.state:%d\n", w->netstat.state);
CloseDown(w, -1);
}
x = (((int)w->core.width) - im->width) / 2;
y = (((int)w->core.height) - im->height) / 2;
XSetWindowBackground (dpy, win, back);
XClearWindow (dpy, win);
XCopyArea (dpy, im->pixmap, win, gc, 0, 0, im->width, im->height, x, y);
/*
* XXX - temporary hack; walk up widget tree to find top most parent (which
* will be a shell) and mash it to have our shape. This will be replaced
* by a special shell widget.
*/
if (w->netstat.shapeit) {
Widget parent;
for (parent = (Widget) w; XtParent(parent);
parent = XtParent(parent)) {
x += parent->core.x + parent->core.border_width;
y += parent->core.y + parent->core.border_width;
}
if (im->mask != w->netstat.shape_cache.mask ||
x != w->netstat.shape_cache.x || y != w->netstat.shape_cache.y) {
XShapeCombineMask (XtDisplay(parent), XtWindow(parent),
ShapeBounding, x, y, im->mask, ShapeSet);
w->netstat.shape_cache.mask = im->mask;
w->netstat.shape_cache.x = x;
w->netstat.shape_cache.y = y;
}
}
return;
}
static void beep (w)
NetstatWidget w;
{
if (w->netstat.volume > 0)
XBell (XtDisplay (w), w->netstat.volume);
return;
}