/*****************************************************************************/ /* asmodem - AfterStep Modem */ /* Version .6 */ /* By Rob Malda */ /* malda@cs.hope.edu */ /* http://www.cs.hope.edu/~malda/ */ /* based Almost Entirely on AfterStep Mail */ /* */ /* asmail - AfterStep Mail */ /* Version 0.31 */ /* By Per Liden */ /* pt95pli@student.hk-r.se */ /* http://www.rby.hk-r.se/~pt95pli */ /* */ /*****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include /* XPM struct and icons ******************************************************/ typedef struct _XpmIcon { Pixmap pixmap; Pixmap mask; XpmAttributes attributes; } XpmIcon; XpmIcon OffModem, OnModem, TModem, RModem, TRModem, Current; #include "XPM/modemoff.xpm" #include "XPM/modem001.xpm" #include "XPM/modem101.xpm" #include "XPM/modem011.xpm" #include "XPM/modemon.xpm" /* Functions *****************************************************************/ int CheckMailBox(char *Mbox); int IsNewMail(char *Mbox); int IsMail(char *Mbox); void Help(void); void CreateWindow(void); void ParseCmdLine(int argc, char *argv[]); void MainLoop(); void GetXPM(void); int FlushExpose(Window w); void RedrawWindow( XpmIcon *v); Pixel GetColor(char *name); /* Global stuff **************************************************************/ #define DEFINTERVAL 3 /* Default interval 2 sec */ #define TRUE 1; #define FALSE 0; #define DEFAULTMODEM "/var/run/cuaa1.if" int withdrawn= FALSE; Display *Disp; Window Root; Window Iconwin; Window Win; char *Geometry= 0; char OnExecute[256] =""; char OffExecute[256] =""; char DisconnectExecute[256]=""; char DefaultModem[256]=DEFAULTMODEM; char *MailBox = 0; int ExecuteFlag = 0; int OffExecuteFlag = 0; int OnExecuteFlag= 0; int DisconnectExecuteFlag=0; int Shape = 0; int hicolor=0; int Interval = DEFINTERVAL; GC WinGC; int CarrierOn = FALSE; #define TICKSPERSEC 6 int Ticks = 0, TicksperInt, sock; int prb = 0, ptb = 0; /*****************************************************************************/ int main(int argc,char *argv[]) { ParseCmdLine(argc, argv); TicksperInt = Interval * TICKSPERSEC; if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("couldn't create IP socket"); exit(1); } CreateWindow(); XSetCommand(Disp,Win,argv,argc); MainLoop(); return 0; } /*****************************************************************************/ void Help() { fprintf(stderr,"asmodem - Version 0.6\n"); fprintf(stderr,"usage: asmodem [-options ...] \n"); fprintf(stderr,"options:\n"); fprintf(stderr," -w withdrawn mode (For WindowMaker's Dock)\n"); fprintf(stderr," -s transparent edge mode\n"); fprintf(stderr," -m modem lockfile (ie /var/lock/LCK..modem) \n"); fprintf(stderr," default is /var/run/cuaa1.if \n"); fprintf(stderr," -u update frequency (default 5 sec)\n"); fprintf(stderr," -p [+|-]x[+|-]y position of asmodem\n"); fprintf(stderr," -d program to execute on click while disconnected (dial?)\n"); fprintf(stderr," -r program to execute on disconnect (redial? beep?)\n"); fprintf(stderr," -h program to excute on click while connected (hangup?)"); fprintf(stderr,"\n"); exit(1); } /****************************************************************************/ void CreateWindow(void) { int i; unsigned int borderwidth ; char *display_name = NULL; char *wname = "asmodem"; XGCValues gcv; unsigned long gcm; XTextProperty name; Pixel back_pix, fore_pix, third_pix; Pixmap pixmask; int screen; int x_fd; int d_depth; int ScreenWidth, ScreenHeight; XSizeHints SizeHints; XWMHints WmHints; XClassHint classHint; /* Open display */ if (!(Disp = XOpenDisplay(display_name))) { fprintf(stderr,"asmodem: can't open display %s\n", XDisplayName(display_name)); exit (1); } screen = DefaultScreen(Disp); Root = RootWindow(Disp, screen); d_depth = DefaultDepth(Disp, screen); x_fd = XConnectionNumber(Disp); ScreenHeight = DisplayHeight(Disp,screen); ScreenWidth = DisplayWidth(Disp,screen); GetXPM(); SizeHints.flags= USSize|USPosition; SizeHints.x = 0; SizeHints.y = 0; back_pix = GetColor("blue"); fore_pix = GetColor("blue"); third_pix = GetColor("white"); XWMGeometry(Disp, screen, Geometry, NULL, (borderwidth =1), &SizeHints, &SizeHints.x,&SizeHints.y,&SizeHints.width, &SizeHints.height, &i); SizeHints.width = OffModem.attributes.width; SizeHints.height= OffModem.attributes.height; Win = XCreateSimpleWindow(Disp,Root,SizeHints.x,SizeHints.y, SizeHints.width,SizeHints.height, borderwidth,fore_pix,back_pix); Iconwin = XCreateSimpleWindow(Disp,Win,SizeHints.x,SizeHints.y, SizeHints.width,SizeHints.height, borderwidth,fore_pix,back_pix); classHint.res_name = "asmodem"; classHint.res_class = "ASModem"; XSetClassHint(Disp, Win, &classHint); XSetWMNormalHints(Disp, Win, &SizeHints); XSelectInput(Disp, Win, (ExposureMask | ButtonPressMask | StructureNotifyMask)); XSelectInput(Disp, Iconwin, (ExposureMask | ButtonPressMask | StructureNotifyMask)); if (XStringListToTextProperty(&wname, 1, &name) ==0) { fprintf(stderr, "asmodem: can't allocate window name\n"); exit(-1); } XSetWMName(Disp, Win, &name); /* Create WinGC */ gcm = GCForeground|GCBackground|GCGraphicsExposures; gcv.foreground = fore_pix; gcv.background = back_pix; gcv.graphics_exposures = True; WinGC = XCreateGC(Disp, Root, gcm, &gcv); WmHints.initial_state = withdrawn?WithdrawnState:NormalState; WmHints.window_group = Win; WmHints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint; WmHints.icon_window = Iconwin; WmHints.icon_x = SizeHints.x; WmHints.icon_y = SizeHints.y; XSetWMHints(Disp, Win, &WmHints); XMapWindow(Disp,Win); RedrawWindow(&Current); } /****************************************************************************/ void ParseCmdLine(int argc, char *argv[]) { char *Argument; int i; for(i = 1; i < argc; i++) { Argument = argv[i]; if (Argument[0] == '-') { switch(Argument[1]) { case 'w': withdrawn=TRUE; continue; case 's': Shape = 1; continue; case 'm': if(++i >= argc) Help(); MailBox = argv[i]; continue; case 'u': if(++i >= argc) Help(); Interval = atoi(argv[i]); if(!Interval) { fprintf(stderr, "asmodem: invalid update frequency specified, using default\n"); Interval = DEFINTERVAL; /* Use default */ } continue; case 'p': if(++i >= argc) Help(); Geometry = argv[i]; continue; case 'd': if(++i >= argc) Help(); strcpy(&OffExecute[0], argv[i]); strcat(&OffExecute[0], " &"); OffExecuteFlag = 1; continue; case 'r': if(++i >= argc) Help(); strcpy(&DisconnectExecute[0], argv[i]); strcat(&DisconnectExecute[0], " &"); DisconnectExecuteFlag = 1; continue; case 'h': if(++i >= argc) Help(); strcpy(&OnExecute[0], argv[i]); strcat(&OnExecute[0], " &"); OnExecuteFlag = 1; continue; default: Help(); } } else Help(); } if(!MailBox) { /* Default Modem Device /dev/modem */ /* fprintf(stderr, "asmodem: no modem specified\n"); */ MailBox = DefaultModem; /* exit(1); */ } } /****************************************************************************/ void MainLoop() { XEvent Event; XpmIcon Prev; struct ifpppstatsreq ifreq; struct ppp_stats stats; int rb, tb; /* Main loop */ while(1) { Prev = Current; Ticks++; if (Ticks == TicksperInt) { Ticks = 0; CheckMailBox(MailBox); //fprintf(stderr, "prb=%d ptb=%d\n",prb,ptb); } //fprintf(stderr, "x "); if (CarrierOn) { memset(&ifreq, 0, sizeof(ifreq)); strcpy(ifreq.ifr_name, "ppp0"); if ((ioctl(sock,SIOCGPPPSTATS,&ifreq) < 0)){ fprintf(stderr, "asmodem: ioctl f*cked\n"); prb = ptb = 0; } else { stats = ifreq.stats; rb = stats.p.ppp_ibytes; tb = stats.p.ppp_obytes; if (rb > prb) { Current = RModem; if (tb > ptb) Current = TRModem; } else if (tb > ptb) Current = TModem; else Current = OnModem; prb = rb; ptb = tb; } } if (Prev.pixmap != Current.pixmap) { //fprintf(stderr, "switch\n"); RedrawWindow(&Current); } /* Check events */ while (XPending(Disp)) { XNextEvent(Disp,&Event); switch(Event.type) { case Expose: /* Redraw window */ if(Event.xexpose.count == 0) RedrawWindow(&Current); break; case ButtonPress: /* Mouseclick */ if (CarrierOn==1) system(OnExecute); else system(OffExecute); break; case DestroyNotify: /* Destroy window */ XFreeGC(Disp, WinGC); XDestroyWindow(Disp, Win); XDestroyWindow(Disp, Iconwin); XCloseDisplay(Disp); exit(0); break; } } XFlush(Disp); usleep(1000000/TICKSPERSEC); } } /****************************************************************************/ int CheckMailBox(char *Mbox) { XpmIcon Prev = Current; if (IsMail(Mbox)) { /* We have a modem! */ if(!IsNewMail(Mbox)) { if(!CarrierOn) { /* fprintf(stderr, "New Modem. I should beep."); */ if(ExecuteFlag == 2) ExecuteFlag = 1; Current = OnModem; CarrierOn=TRUE; } } } else { if(CarrierOn) { CarrierOn=FALSE; /* fprintf(stderr, "I have lost modem. I should beep."); */ system(DisconnectExecute); if(ExecuteFlag == 2) ExecuteFlag = 1; Current = OffModem; } } return (Prev.pixmap != Current.pixmap); } /****************************************************************************/ int IsNewMail(char *Mbox) { FILE* MailFile; int Ret = 0; char Buffer[30] = ""; int WasStatus = 1; int NewMailn = 0; /* MailFile = fopen(Mbox, "r"); while(!feof(MailFile)) { fgets(Buffer, 29, MailFile); if(!strncmp(Buffer, "From ", 5)) { if(!WasStatus) NewMailn++; WasStatus=0; } else if(!strncmp(Buffer, "Status: RO", 10)) WasStatus = 1; } fclose(MailFile); return (NewMailn||!WasStatus); */ return 0; } /****************************************************************************/ int IsMail(char *Mbox) { FILE* MailFile = 0; int Ret = 0; /* MailFile = fopen(Mbox, "r"); if(MailFile == 0) Ret = 0; else { fgetc(MailFile); if(feof(MailFile)) Ret = 0; else Ret = 1; fclose(MailFile); } return Ret; */ if ((MailFile=fopen(Mbox,"r"))==NULL) return 0; else { fclose(MailFile); return 1; } } /****************************************************************************/ void GetXPM(void) { XWindowAttributes Attributes; int Ret; XGetWindowAttributes(Disp,Root,&Attributes); OffModem.attributes.valuemask |= (XpmReturnPixels|XpmReturnExtensions); Ret = XpmCreatePixmapFromData(Disp, Root, modemoff, &OffModem.pixmap, &OffModem.mask, &OffModem.attributes); if(Ret != XpmSuccess) { fprintf(stderr, "asmodem: not enough free color cells\n"); exit(1); } OnModem.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); Ret = XpmCreatePixmapFromData(Disp, Root, modem001, &OnModem.pixmap, &OnModem.mask, &OnModem.attributes); TModem.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); Ret = XpmCreatePixmapFromData(Disp, Root, modem011, &TModem.pixmap, &TModem.mask, &TModem.attributes); RModem.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); Ret = XpmCreatePixmapFromData(Disp, Root, modem101, &RModem.pixmap, &RModem.mask, &RModem.attributes); TRModem.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); Ret = XpmCreatePixmapFromData(Disp, Root, modemon, &TRModem.pixmap, &TRModem.mask, &TRModem.attributes); Current = OffModem; } /****************************************************************************/ int FlushExpose(Window w) { XEvent dummy; int i=0; while (XCheckTypedWindowEvent (Disp, w, Expose, &dummy))i++; return i; } /****************************************************************************/ void RedrawWindow(XpmIcon *Icon) { FlushExpose(Win); FlushExpose(Iconwin); if(Shape==1) { XShapeCombineMask(Disp, Win, ShapeBounding, 0, 0, Icon->mask, ShapeSet); XShapeCombineMask(Disp, Iconwin, ShapeBounding, 0, 0, Icon->mask, ShapeSet); } XSetClipOrigin(Disp,WinGC,0,0); XSetClipMask(Disp,WinGC,Icon->mask); XCopyArea(Disp,Icon->pixmap,Win,WinGC, 0,0,Icon->attributes.width, Icon->attributes.height,0,0); XCopyArea(Disp,Icon->pixmap,Iconwin,WinGC, 0,0,Icon->attributes.width, Icon->attributes.height,0,0); } /****************************************************************************/ Pixel GetColor(char *ColorName) { XColor Color; XWindowAttributes Attributes; XGetWindowAttributes(Disp,Root,&Attributes); Color.pixel = 0; if (!XParseColor (Disp, Attributes.colormap, ColorName, &Color)) fprintf(stderr,"asmodem: can't parse %s\n", ColorName); else if(!XAllocColor (Disp, Attributes.colormap, &Color)) fprintf(stderr,"asmodem: can't allocate %s\n", ColorName); return Color.pixel; }