1 /****************************************************************************
2  * This module is all original code
3  * by Rob Nation
4  * Copyright 1993, Robert Nation
5  *     You may use this code for any purpose, as long as the original
6  *     copyright remains in the source code and all documentation
7  ****************************************************************************/
8 
9 /***********************************************************************
10  *
11  * code for launching afterstep modules.
12  *
13  ***********************************************************************/
14 
15 #include "../configure.h"
16 
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <signal.h>
20 #include <string.h>
21 #include <fcntl.h>
22 #include <ctype.h>
23 #include <X11/keysym.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 
27 #include "afterstep.h"
28 #include "menus.h"
29 #include "misc.h"
30 #include "parse.h"
31 #include "screen.h"
32 #include "module.h"
33 
34 
35 int npipes;
36 int *readPipes;
37 int *writePipes;
38 int *pipeOn;
39 unsigned long *PipeMask;
40 struct queue_buff_struct **pipeQueue;
41 
42 AFTER_INLINE int PositiveWrite(int module, unsigned long *ptr, int size);
43 void DeleteQueueBuff(int module);
44 void AddToQueue(int module, unsigned long *ptr, int size, int done);
45 
initModules(void)46 void initModules(void)
47 {
48   int i;
49 
50   npipes = GetFdWidth();
51 
52   writePipes = (int *)safemalloc(sizeof(int)*npipes);
53   readPipes = (int *)safemalloc(sizeof(int)*npipes);
54   pipeOn = (int *)safemalloc(sizeof(int)*npipes);
55   PipeMask = (unsigned long *)safemalloc(sizeof(unsigned long)*npipes);
56   pipeQueue=(struct queue_buff_struct **)
57     safemalloc(sizeof(struct queue_buff_struct *)*npipes);
58 
59   for(i=0;i<npipes;i++)
60     {
61       writePipes[i]= -1;
62       readPipes[i]= -1;
63       pipeOn[i] = -1;
64       PipeMask[i] = MAX_MASK;
65       pipeQueue[i] = (struct queue_buff_struct *)NULL;
66 
67     }
68 }
69 
ClosePipes(void)70 void ClosePipes(void)
71 {
72   int i;
73   for(i=0;i<npipes;i++)
74     {
75       if(writePipes[i]>0)
76 	{
77 	  close(writePipes[i]);
78 	  close(readPipes[i]);
79 	}
80       while(pipeQueue[i] != NULL)
81 	{
82 	  DeleteQueueBuff(i);
83 	}
84     }
85 }
86 
executeModule(char * action,FILE * fd,char ** win,int * context)87 void executeModule(char *action,FILE *fd, char **win, int *context)
88 {
89   int afterstep_to_app[2],app_to_afterstep[2];
90   int i,val;
91   char command[256];
92   char *cptr;
93   char *aptr;
94   char *args[10];
95   char *arg1 = NULL;
96   char arg2[40];
97   char arg3[40];
98   char arg5[40];
99   char arg6[40];
100   char *end;
101   extern char *ModulePath;
102   extern FILE *config_fd;
103   extern char *afterstep_file;
104 
105   if(action == NULL)
106     return;
107   strcpy(command,action);
108 
109   cptr = command;
110   while((isspace(*cptr))&&(*cptr != '\n')&&(*cptr != 0))
111     cptr++;
112 
113   end = cptr;
114   while((!(isspace(*end))&&(*end != '\n'))&&(*end != 0)&&(end <(command+256)))
115     end++;
116 
117   if((*end == 0)||(end >= command+256))
118     aptr = NULL;
119   else
120     aptr = end+1;
121   *end = 0;
122 
123   if(aptr)
124     {
125       while((isspace(*aptr)||(*aptr=='\n'))&&(*aptr!=0)&&(aptr<(command+256)))
126 	aptr++;
127       if((*aptr == 0)||(*aptr == '\n'))
128 	aptr = NULL;
129     }
130 
131   arg1 = findIconFile(cptr,ModulePath,X_OK);
132   if(arg1 == NULL)
133     {
134       fprintf(stderr,"AfterStep: No such module %s %s\n",ModulePath,cptr);
135       return;
136     }
137 
138   /* Look for an available pipe slot */
139   i=0;
140   while((i<npipes) && (writePipes[i] >=0))
141     i++;
142   if(i>=npipes)
143     {
144       fprintf(stderr,"afterstep: Too many Accessories!\n");
145       return;
146     }
147 
148   /* I want one-ended pipes, so I open two two-ended pipes,
149    * and close one end of each. I need one ended pipes so that
150    * I can detect when the module crashes/malfunctions */
151   if(pipe(afterstep_to_app)!=0)
152     {
153       fprintf(stderr,"AfterStep: Failed to open pipe\n");
154       return;
155     }
156   if(pipe(app_to_afterstep)!=0)
157     {
158       fprintf(stderr,"AfterStep: Failed to open pipe2\n");
159       close(afterstep_to_app[0]);
160       close(afterstep_to_app[1]);
161       return;
162     }
163 
164 
165   val = fork();
166   if(val > 0)
167     {
168       /* This fork remains running afterstep */
169       /* close appropriate descriptors from each pipe so
170        * that afterstep will be able to tell when the app dies */
171       close(app_to_afterstep[1]);
172       close(afterstep_to_app[0]);
173 
174       /* add these pipes to afterstep's active pipe list */
175       writePipes[i] = afterstep_to_app[1];
176       readPipes[i] = app_to_afterstep[0];
177       pipeOn[i] = -1;
178       PipeMask[i] = MAX_MASK;
179       free(arg1);
180       pipeQueue[i] = NULL;
181 
182       /* make the PositiveWrite pipe non-blocking. Don't want to jam up
183 	 afterstep because of an uncooperative module */
184       fcntl(writePipes[i],F_SETFL,O_NDELAY);
185       /* Mark the pipes close-on exec so other programs
186        * won`t inherit them */
187       if (fcntl(readPipes[i], F_SETFD, 1) == -1)
188 	afterstep_err("module close-on-exec failed",NULL,NULL,NULL);
189       if (fcntl(writePipes[i], F_SETFD, 1) == -1)
190 	afterstep_err("module close-on-exec failed",NULL,NULL,NULL);
191     }
192   else if (val ==0)
193     {
194       /* this is  the child */
195       /* need to close config_fd if its still open! */
196       if(config_fd != (FILE *)NULL)
197 	/* Fixes some funny stuff with svr4 and stream IO */
198 	/* fclose(config_fd) */
199 	close(fileno(config_fd));
200 
201       /* this fork execs the module */
202       close(afterstep_to_app[1]);
203       close(app_to_afterstep[0]);
204       sprintf(arg2,"%d",app_to_afterstep[1]);
205       sprintf(arg3,"%d",afterstep_to_app[0]);
206       sprintf(arg5,"%lx",(unsigned long)win);
207       sprintf(arg6,"%lx",(unsigned long)context);
208       args[0]=arg1;
209       args[1]=arg2;
210       args[2]=arg3;
211       args[3]=afterstep_file;
212       args[4]=arg5;
213       args[5]=arg6;
214       if(aptr != NULL)
215 	{
216 	  args[6] = aptr;
217 	  args[7] = 0;
218 	}
219       else
220 	args[6]= 0;
221       execvp(arg1,args);
222       fprintf(stderr,"Execution of module failed: %s",arg1);
223       perror("");
224       close(app_to_afterstep[1]);
225       close(afterstep_to_app[0]);
226       exit(1);
227     }
228   else
229     {
230       fprintf(stderr,"Fork failed\n");
231       free(arg1);
232     }
233   return;
234 }
235 
HandleModuleInput(Window w,int channel)236 int HandleModuleInput(Window w, int channel)
237 {
238   char text[256];
239   int size;
240   int cont,n;
241   char *newaction = NULL;
242 
243   /* Already read a (possibly NULL) window id from the pipe,
244    * Now read an afterstep bultin command line */
245   n = read(readPipes[channel], &size, sizeof(int));
246   if(n < sizeof(int))
247     {
248       KillModule(channel,1);
249       return;
250     }
251 
252   if(size >255)
253     {
254       fprintf(stderr,"Module command is too big (%d)\n",size);
255       size=255;
256     }
257 
258   pipeOn[channel] = 1;
259 
260   n = read(readPipes[channel],text, size);
261   if(n < size)
262     {
263       KillModule(channel,2);
264       return;
265     }
266 
267   text[n]=0;
268   n = read(readPipes[channel],&cont, sizeof(int));
269   if(n < sizeof(int))
270     {
271       KillModule(channel,3);
272       return;
273     }
274   if(cont == 0)
275     {
276       KillModule(channel,4);
277     }
278   if(strlen(text)>0)
279     {
280       char function[256],*ptr;
281       MenuRoot *mr=0;
282       char *item=NULL;
283       extern int func_val_1,func_val_2,func,Context;
284       extern struct config func_config[];
285       extern unsigned PopupCount;
286       extern MenuRoot *PopupTable[MAXPOPUPS];
287       ASWindow *tmp_win;
288       extern char *orig_tline;
289       int n,unit_val_1,unit_val_2;
290       char unit_1, unit_2;
291 
292 
293       orig_tline = text;
294       Event.xany.type = ButtonRelease;
295       Event.xany.window = w;
296 
297       func_val_1 = 0;
298       func_val_2 = 0;
299       unit_1 = 's';
300       unit_2 = 's';
301       n = sscanf(text,"%s %d %d",function,&func_val_1,&func_val_2);
302       if(n != 3)
303 	n = sscanf(text,"%s %d%c %d%c",function,&func_val_1,&unit_1,&func_val_2,&unit_2);
304 
305       if(mystrcasecmp(function,"SET_MASK")==0)
306 	{
307 	  PipeMask[channel] = func_val_1;
308 	  return;
309 	}
310       if(mystrcasecmp(function,"UNLOCK")==0)
311         {
312 	  return 66;
313 	}
314       func = F_NOP;
315       match_string(func_config,function,"bad module function:",NULL);
316       if((func == F_POPUP)||(func == F_FUNCTION))
317 	{
318 	  unsigned i;
319 	  ptr = stripcpy2(text,0,True);
320 	  if(ptr != NULL)
321 	    for (i = 0; i < PopupCount; i++)
322 	      if (mystrcasecmp(PopupTable[i]->name,ptr) == 0)
323 		{
324 		  mr = PopupTable[i];
325 		  break;
326 		}
327 	  if (!mr)
328 	    {
329 	      no_popup(ptr);
330 	      func = F_NOP;
331 	    }
332 	}
333       else if((func == F_EXEC)||(func == F_RESTART)||
334 	      (func == F_CIRCULATE_UP)||(func == F_CIRCULATE_DOWN)||
335 	      (func == F_WARP)||(func == F_MODULE))
336 	{
337 	  if((func == F_EXEC)||(func == F_RESTART)||(func== F_MODULE))
338 	    {
339 	      item = stripcpy2(text,0,True);
340 	      newaction = stripcpy3(text,True);
341 	    }
342 	  else
343 	    {
344 	      item = stripcpy2(text,0,False);
345 	      newaction = stripcpy3(text,False);
346 	    }
347 	}
348       if (XFindContext (dpy, w, ASContext, (caddr_t *) &tmp_win) == XCNOENT)
349 	{
350 	  tmp_win = NULL;
351 	  w = None;
352 	}
353       if(tmp_win)
354 	{
355 	  Event.xbutton.button = 1;
356 	  Event.xbutton.x_root = tmp_win->frame_x;
357 	  Event.xbutton.y_root = tmp_win->frame_y;
358 	  Event.xbutton.x = 0;
359 	  Event.xbutton.y = 0;
360 	  Event.xbutton.subwindow = None;
361 	}
362       else
363 	{
364 	  Event.xbutton.button = 1;
365 	  Event.xbutton.x_root = 0;
366 	  Event.xbutton.y_root = 0;
367 	  Event.xbutton.x = 0;
368 	  Event.xbutton.y = 0;
369 	  Event.xbutton.subwindow = None;
370 	}
371       if(unit_1 == 'p')
372 	unit_val_1 = 100;
373       else
374 	unit_val_1 = Scr.MyDisplayWidth;
375       if(unit_2 == 'p')
376 	unit_val_2 = 100;
377       else
378 	unit_val_2 = Scr.MyDisplayHeight;
379 
380       Context = GetContext(tmp_win,&Event,&w);
381       ExecuteFunction(func,newaction, w, tmp_win, &Event, Context,
382 		      func_val_1,func_val_2,unit_val_1,unit_val_2,mr,channel);
383     }
384   return;
385 }
386 
387 
DeadPipe(int nonsense)388 void DeadPipe(int nonsense)
389 {
390   signal(SIGPIPE, DeadPipe);
391 }
392 
393 
KillModule(int channel,int place)394 void KillModule(int channel, int place)
395 {
396   close(readPipes[channel]);
397   close(writePipes[channel]);
398 
399   readPipes[channel] = -1;
400   writePipes[channel] = -1;
401   pipeOn[channel] = -1;
402   while(pipeQueue[channel] != NULL)
403     {
404       DeleteQueueBuff(channel);
405     }
406   return;
407 }
408 
409 
Broadcast(unsigned long event_type,unsigned long num_datum,unsigned long data1,unsigned long data2,unsigned long data3,unsigned long data4,unsigned long data5,unsigned long data6,unsigned long data7)410 void Broadcast(unsigned long event_type, unsigned long num_datum,
411 	       unsigned long data1, unsigned long data2, unsigned long data3,
412 	       unsigned long data4, unsigned long data5, unsigned long data6,
413 	       unsigned long data7)
414 {
415   int i;
416   unsigned long body[10];
417 
418   body[0] = START_FLAG;
419   body[1] = event_type;
420   body[2] = num_datum+3;
421 
422   if(num_datum>0)
423     body[3] = data1;
424   if(num_datum>1)
425     body[4] = data2;
426   if(num_datum>2)
427     body[5] = data3;
428   if(num_datum>3)
429     body[6] = data4;
430   if(num_datum>4)
431     body[7] = data5;
432   if(num_datum>5)
433     body[8] = data6;
434   if(num_datum>6)
435     body[9] = data7;
436 
437   for(i=0;i<npipes;i++)
438     PositiveWrite(i,body, (num_datum+3)*sizeof(unsigned long));
439 }
440 
441 
442 
443 
SendPacket(int module,unsigned long event_type,unsigned long num_datum,unsigned long data1,unsigned long data2,unsigned long data3,unsigned long data4,unsigned long data5,unsigned long data6,unsigned long data7)444 void SendPacket(int module, unsigned long event_type, unsigned long num_datum,
445 	       unsigned long data1, unsigned long data2, unsigned long data3,
446 	       unsigned long data4, unsigned long data5, unsigned long data6,
447 	       unsigned long data7)
448 {
449   unsigned long body[10];
450 
451   body[0] = START_FLAG;
452   body[1] = event_type;
453   body[2] = num_datum+3;
454 
455   if(num_datum>0)
456     body[3] = data1;
457   if(num_datum>1)
458     body[4] = data2;
459   if(num_datum>2)
460     body[5] = data3;
461   if(num_datum>3)
462     body[6] = data4;
463   if(num_datum>4)
464     body[7] = data5;
465   if(num_datum>5)
466     body[8] = data6;
467   if(num_datum>6)
468     body[9] = data7;
469   PositiveWrite(module,body,(num_datum+3)*sizeof(unsigned long));
470 }
471 
SendConfig(int module,unsigned long event_type,ASWindow * t)472 void SendConfig(int module, unsigned long event_type, ASWindow *t)
473 {
474   unsigned long body[MAX_BODY_SIZE+HEADER_SIZE];
475 
476   body[0] = START_FLAG;
477   body[1] = event_type;
478   body[2] = 27;
479   body[3] = t->w;
480   body[4] = t->frame;
481   body[5] = (unsigned long)t;
482   body[6] = t->frame_x;
483   body[7] = t->frame_y;
484   body[8] = t->frame_width;
485   body[9] = t->frame_height;
486   body[10] = t->Desk;
487   body[11] = t->flags;
488   body[12] = t->title_height;
489   body[13] = t->boundary_width;
490   body[14] = t->hints.base_width;
491   body[15] = t->hints.base_height;
492   body[16] = t->hints.width_inc;
493   body[17] = t->hints.height_inc;
494   body[18] = t->hints.min_width;
495   body[19] = t->hints.min_height;
496   body[20] = t->hints.max_width;
497   body[21] = t->hints.max_height;
498   body[22] = 0;
499   body[23] = t->icon_pixmap_w;
500   body[24] = t->hints.win_gravity;
501   body[25] = t->TextPixel;
502   body[26] = t->BackPixel;
503 
504   PositiveWrite(module,body,27*sizeof(unsigned long));
505 }
506 
507 
BroadcastConfig(unsigned long event_type,ASWindow * t)508 void BroadcastConfig(unsigned long event_type, ASWindow *t)
509 {
510   unsigned long body[MAX_BODY_SIZE+HEADER_SIZE];
511   int i;
512 
513   body[0] = START_FLAG;
514   body[1] = event_type;
515   body[2] = 27;
516   body[3] = t->w;
517   body[4] = t->frame;
518   body[5] = (unsigned long)t;
519   body[6] = t->frame_x;
520   body[7] = t->frame_y;
521   body[8] = t->frame_width;
522   body[9] = t->frame_height;
523   body[10] = t->Desk;
524   body[11] = t->flags;
525   body[12] = t->title_height;
526   body[13] = t->boundary_width;
527   body[14] = t->hints.base_width;
528   body[15] = t->hints.base_height;
529   body[16] = t->hints.width_inc;
530   body[17] = t->hints.height_inc;
531   body[18] = t->hints.min_width;
532   body[19] = t->hints.min_height;
533   body[20] = t->hints.max_width;
534   body[21] = t->hints.max_height;
535   body[22] = 0;
536   body[23] = t->icon_pixmap_w;
537   body[24] = t->hints.win_gravity;
538   body[25] = t->TextPixel;
539   body[26] = t->BackPixel;
540 
541   for(i=0;i<npipes;i++)
542     {
543       PositiveWrite(i,body,27*sizeof(unsigned long));
544     }
545 }
546 
BroadcastName(unsigned long event_type,unsigned long data1,unsigned long data2,unsigned long data3,char * name)547 void BroadcastName(unsigned long event_type, unsigned long data1,
548 		   unsigned long data2, unsigned long data3, char *name)
549 {
550   int l,i;
551   unsigned long *body;
552 
553 
554   if(name==NULL)
555     return;
556   l=strlen(name)/(sizeof(unsigned long))+7;
557   body = (unsigned long *)safemalloc(l*sizeof(unsigned long));
558 
559   body[0] = START_FLAG;
560   body[1] = event_type;
561   body[2] = l;
562 
563   body[3] = data1;
564   body[4] = data2;
565   body[5] = data3;
566   strcpy((char *)&body[6],name);
567 
568 
569   for(i=0;i<npipes;i++)
570     PositiveWrite(i,(unsigned long *)body, l*sizeof(unsigned long));
571 
572   free(body);
573 
574 }
575 
576 
SendName(int module,unsigned long event_type,unsigned long data1,unsigned long data2,unsigned long data3,char * name)577 void SendName(int module, unsigned long event_type,
578 	      unsigned long data1,unsigned long data2,
579 	      unsigned long data3, char *name)
580 {
581   int l;
582   unsigned long *body;
583 
584   if(name == NULL)
585     return;
586   l=strlen(name)/(sizeof(unsigned long))+7;
587   body = (unsigned long *)safemalloc(l*sizeof(unsigned long));
588 
589   body[0] = START_FLAG;
590   body[1] = event_type;
591   body[2] = l;
592 
593   body[3] = data1;
594   body[4] = data2;
595   body[5] = data3;
596   strcpy((char *)&body[6],name);
597 
598   PositiveWrite(module,(unsigned long *)body, l*sizeof(unsigned long));
599 
600   free(body);
601 }
602 
603 
604 
605 #include <sys/errno.h>
PositiveWrite(int module,unsigned long * ptr,int size)606 AFTER_INLINE int PositiveWrite(int module, unsigned long *ptr, int size)
607 {
608   if((pipeOn[module]<0)||(!((PipeMask[module]) & ptr[1])))
609     return -1;
610 
611   AddToQueue(module,ptr,size,0);
612 
613   if (PipeMask[module] & M_LOCKONSEND)
614     {
615       Window targetWindow;
616       int e;
617 
618 
619       FlushQueue(module);
620 
621       fcntl(readPipes[module],F_SETFL,0);
622 
623       while ((e = read(readPipes[module],&targetWindow, sizeof(Window))) > 0)
624         {
625           if (HandleModuleInput(targetWindow,module) == 66)
626 	      break;
627 	}
628       if (e <= 0)
629           KillModule(module,10);
630 
631       fcntl(readPipes[module],F_SETFL,O_NDELAY);
632     }
633 
634   return size;
635 }
636 
AddToQueue(int module,unsigned long * ptr,int size,int done)637 void AddToQueue(int module, unsigned long *ptr, int size, int done)
638 {
639   struct queue_buff_struct *c,*e;
640   unsigned long *d;
641 
642   c = (struct queue_buff_struct *)safemalloc(sizeof(struct queue_buff_struct));
643   c->next = NULL;
644   c->size = size;
645   c->done = done;
646   d = (unsigned long *)safemalloc(size);
647   c->data = d;
648   memcpy(d,ptr,size);
649 
650   e = pipeQueue[module];
651   if(e == NULL)
652     {
653       pipeQueue[module] = c;
654       return;
655     }
656   while(e->next != NULL)
657     e = e->next;
658   e->next = c;
659 }
660 
DeleteQueueBuff(int module)661 void DeleteQueueBuff(int module)
662 {
663   struct queue_buff_struct *a;
664 
665   if(pipeQueue[module] == NULL)
666      return;
667   a = pipeQueue[module];
668   pipeQueue[module] = a->next;
669   free(a->data);
670   free(a);
671   return;
672 }
673 
FlushQueue(int module)674 void FlushQueue(int module)
675 {
676   char *dptr;
677   struct queue_buff_struct *d;
678   int a;
679   extern int errno;
680 
681   if((pipeOn[module] <= 0)||(pipeQueue[module] == NULL))
682     return;
683 
684   while(pipeQueue[module] != NULL)
685     {
686       d = pipeQueue[module];
687       dptr = (char *)d->data;
688       while(d->done < d->size)
689 	{
690 	  a = write(writePipes[module],&dptr[d->done], d->size - d->done);
691 	  if(a >=0)
692 	    d->done += a;
693 	  /* the write returns EWOULDBLOCK or EAGAIN if the pipe is full.
694 	   * (This is non-blocking I/O). SunOS returns EWOULDBLOCK, OSF/1
695 	   * returns EAGAIN under these conditions. Hopefully other OSes
696 	   * return one of these values too. Solaris 2 doesn't seem to have
697 	   * a man page for write(2) (!) */
698 	  else if ((errno == EWOULDBLOCK)||(errno == EAGAIN)||(errno==EINTR))
699 	    {
700 	      return;
701 	    }
702 	  else
703 	    {
704 	      KillModule(module,123);
705 	      return;
706 	    }
707 	}
708       DeleteQueueBuff(module);
709     }
710 }
711