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