Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / lib / DtSvc / DtEncap / spc.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * File:         spc.c $XConsortium: spc.c /main/6 1996/06/21 17:33:08 ageorge $
25  * Language:     C
26  *
27  * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
28  *
29  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
30  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
31  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
32  * (c) Copyright 1993, 1994 Novell, Inc.                                *
33  */
34
35 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
36 #include <signal.h>
37 #include <SPC/spcP.h>
38 #include <SPC/spc-proto.h>
39 #include <bms/spc.h>
40 #include "DtSvcLock.h"
41
42 /* spc.c */
43 int SPC_Process_Single_Prot_Request (protocol_request_ptr req, SPC_Channel_Ptr channel);
44
45
46 /* This is the SPC error number variable */
47 /* extern int XeSPCErrorNumber; */
48
49 /* Externals */
50
51 extern int SPC_Initialized;
52 extern SPC_Channel_Ptr spc_activation_list;
53 extern SPC_Connection_Ptr connection_list;
54 extern SPC_Connection_Ptr read_terminator;
55 extern XeString official_hostname;
56
57 int max_fds = 0;   /* Set up below. */
58
59 /*----------------------------------------------------------------------+*/
60 void 
61 spc_init_fds(void)
62 /*----------------------------------------------------------------------+*/
63 {
64    _DtSvcProcessLock();
65    if (!max_fds)
66 #     ifdef __bsd
67          max_fds = getdtablesize();
68 #     else
69          max_fds = (int)sysconf(_SC_OPEN_MAX);
70 #     endif
71    _DtSvcProcessUnlock();
72 }
73
74 /*
75  ***
76  *** Sub-Process Control access routines.  These are just functional
77  *** interfaces to the underlying methods.
78  ***
79 */
80
81 /*----------------------------------------------------------------------+*/
82 SPC_Channel_Ptr XeSPCOpen(XeString hostname,
83                           int iomode)
84 /*----------------------------------------------------------------------+*/
85 {
86   /* Attempt to open an SPC channel - return TRUE if we succeed */
87   SPC_Channel_Ptr channel;
88
89   /* Check for initialization */
90   _DtSvcProcessLock();
91   if(!SPC_Initialized)
92       if(SPC_Initialize() == SPC_ERROR) {
93           _DtSvcProcessUnlock();
94           return(SPC_ERROR);
95       }
96   _DtSvcProcessUnlock();
97
98   /* The user specified iomode needs to be processed before we can use it.
99      Process the puppy. */
100
101   iomode=SPC_Transform_Iomode(iomode);
102   if(iomode==SPC_ERROR)
103     return(SPC_ERROR);
104        
105   /* Get a new channel object */
106   
107   channel=SPC_Initialize_Channel(hostname, iomode);
108
109   /* check that everything was okay */
110   
111   if(channel==SPC_ERROR)
112     return(SPC_ERROR);
113   
114   /* call the open method for it */
115
116   return((SPC_Channel_Ptr) mempf2(channel, open, iomode, hostname));
117
118 }
119
120 /*----------------------------------------------------------------------+*/
121 int
122 XeSPCClose(SPC_Channel_Ptr channel)
123 /*----------------------------------------------------------------------+*/
124 {
125   if(channel==SPC_ERROR) {
126     SPC_Error(SPC_Bad_Argument);
127     return(SPC_ERROR);
128   }
129
130   if(IS_ACTIVE(channel))
131     XeSPCKillProcess(channel, FALSE);
132
133   if(IS_SPCIO_DELAY_CLOSE(channel->IOMode)) {
134     channel->IOMode |= SPCIO_DO_CLOSE;
135     return(TRUE);
136   }
137   
138   channel->IOMode &= ~SPCIO_DO_CLOSE;
139   
140   return(mempf0(channel, close));
141   
142 }
143
144 /*----------------------------------------------------------------------+*/
145 int
146 XeSPCReset(SPC_Channel_Ptr channel)
147 /*----------------------------------------------------------------------+*/
148 {
149
150   if(channel==SPC_ERROR) {
151     SPC_Error(SPC_Bad_Argument);
152     return(SPC_ERROR);
153   }
154
155   if(IS_ACTIVE(channel))
156     XeSPCKillProcess(channel, FALSE);
157   
158   channel->IOMode &= ~SPCIO_ACTIVE;
159
160   if(mempf0(channel, reset)==SPC_ERROR)
161     return(SPC_ERROR);
162   
163   return(TRUE);
164   
165 }
166
167 /*----------------------------------------------------------------------+*/
168 int
169 XeSPCRead(SPC_Channel_Ptr channel,
170           int connector,           /* STDOUT or STDERR */
171           XeString buffer,
172           int length)
173 /*----------------------------------------------------------------------+*/
174 {
175
176   int n;
177   
178   /* check for legal arguments */
179   
180   if (channel==SPC_ERROR || !buffer ||
181       !(connector==STDOUT || connector==STDERR) ||
182       (length < 0)) {
183     SPC_Error(SPC_Bad_Argument);
184     return(SPC_ERROR);
185   }
186
187   /* check state of the channel */
188   if (!IS_DATA(channel) || !IS_SPCIO_DATA(channel->wires[connector]->flags))
189     return(0);
190   
191   /* call the read filter */
192
193   do {
194     n=(*channel->read_filter)(channel, connector, buffer, length);
195   } while(n == (EXCEPT_FLAG));
196   
197   /* Check for an error */
198
199   if (n == SPC_ERROR)
200     return(SPC_ERROR);
201   
202   return(n);
203 }
204
205   
206 /*----------------------------------------------------------------------+*/
207 int
208 XeSPCWrite(SPC_Channel_Ptr channel,
209            XeString buffer,
210            int length)
211 /*----------------------------------------------------------------------+*/
212 {
213   int n;
214   
215   /* check for legal arguments */
216   
217   if (channel==SPC_ERROR || !buffer || (length<0)) {
218     SPC_Error(SPC_Bad_Argument);
219     return(SPC_ERROR);
220   }
221
222   /* check the state of the channel */
223
224   if(!IS_ACTIVE(channel)) {
225     SPC_Error(SPC_Inactive_Channel);
226     return(SPC_ERROR);
227   }
228   
229   /* call the write method */
230   
231   n=mempf2(channel, write, buffer, length);
232   
233   return(n);
234 }
235
236 /*----------------------------------------------------------------------+*/
237 int
238 XeSPCActive(SPC_Channel_Ptr channel)
239 /*----------------------------------------------------------------------+*/
240 {
241
242   if (channel==SPC_ERROR) {
243     SPC_Error(SPC_Bad_Argument);
244     return(SPC_ERROR);
245   }
246   
247   /* Is the passed channel active? */
248   return (IS_ACTIVE(channel));
249 }
250
251 /*----------------------------------------------------------------------+*/
252 int
253 XeSPCData(SPC_Channel_Ptr channel)
254 /*----------------------------------------------------------------------+*/
255 {
256
257   if(channel==SPC_ERROR) {
258     SPC_Error(SPC_Bad_Argument);
259     return(SPC_ERROR);
260   }
261   
262   return(IS_DATA(channel));
263
264 }
265
266 /*----------------------------------------------------------------------+*/
267 int
268 XeSPCExecuteProcess(SPC_Channel_Ptr channel)
269 /*----------------------------------------------------------------------+*/
270 {
271   int retval;
272
273   if (channel==SPC_ERROR) {
274     SPC_Error(SPC_Bad_Argument);
275     return(SPC_ERROR);
276   }
277   
278   if(IS_ACTIVE(channel) || IS_DATA(channel)) {
279     SPC_Error(SPC_Active_Channel);
280     return(SPC_ERROR);
281   }
282
283   if((retval=mempf0(channel, exec_proc))==SPC_ERROR)
284     return(SPC_ERROR);
285
286   if (IS_SPCIO_WAIT(channel->IOMode)) {
287     /* Wait for sub-process to finish */
288     SPC_Wait_For_Termination(channel);
289   }
290   
291   return(retval);
292
293 }
294
295 /*----------------------------------------------------------------------+*/
296 int
297 XeSPCSignalProcess(SPC_Channel_Ptr channel,
298                    int sig)
299 /*----------------------------------------------------------------------+*/
300 {
301   
302   if ((channel==SPC_ERROR) ||
303       (channel->pid <= 0) ||
304       (sig < 0) 
305 #ifdef NOT_IN_XPG3_YET      
306       || (sig>=NSIG)    /* Not a good idea for interoperability anyway */
307 #endif
308       ) {
309     SPC_Error(SPC_Bad_Argument);
310     return(SPC_ERROR);
311   }
312
313   /* This routine does not check to see if the channel is active. */
314
315   return(mempf1(channel, signal, sig));
316 }
317
318 /*----------------------------------------------------------------------+*/
319 int
320 XeSPCAddInput(SPC_Channel_Ptr   channel,
321               SbInputHandlerProc handler,
322 /*----------------------------------------------------------------------+*/
323               void *            client_data)
324 {
325   if(!channel) {
326     SPC_Error(SPC_Bad_Argument);
327     return(SPC_ERROR);
328   }
329   
330   if(!handler && !channel->Input_Handler)
331     return(TRUE);
332
333   if(handler) {
334     channel->Input_Handler = handler;
335     channel->client_data   = client_data;
336   }
337
338   return(mempf2(channel, add_input, handler, client_data));
339     
340 }
341
342
343 /*----------------------------------------------------------------------+*/
344 int
345 XeSPCRegisterTerminator(SPC_Channel_Ptr                 channel,
346                         SPC_TerminateHandlerType        terminator,
347                         void *                          client_data)
348 /*----------------------------------------------------------------------+*/
349 {
350
351   SPC_Connection_Ptr conn;
352   
353   if(channel==SPC_ERROR) {
354     SPC_Error(SPC_Bad_Argument);
355     return(SPC_ERROR);
356   }
357
358   /* Okay.  If we have a pty channel, we have to check that we
359      have an input handler.  I don't like doing this here, but ther
360      are no methods for this routine, so it has to be done. */
361
362   if(IS_SPCIO_PTY(channel->IOMode) && !channel->Input_Handler) {
363     SPC_Error(SPC_Bad_Argument);
364     return(SPC_ERROR);
365   }
366
367   channel->IOMode |= SPCIO_SYNC_TERMINATOR;
368   if(terminator) {
369     channel->Terminate_Handler = terminator;
370     channel->Terminate_Data    = client_data;
371   }
372
373   conn=SPC_Channel_Terminator_Connection(channel);
374   if(conn->termination_id == -1)
375     SPC_XtAddInput(channel, &conn->termination_id, conn->sid,
376                    SPC_Conditional_Packet_Handler, SPC_Terminator);
377   
378   return(TRUE);
379   
380 }
381
382
383 /*----------------------------------------------------------------------+*/
384 int
385 XeSPCAttach(SPC_Channel_Ptr channel,
386             int pid)
387 /*----------------------------------------------------------------------+*/
388
389 {
390   if(channel==SPC_ERROR || pid<=0) {
391     SPC_Error(SPC_Bad_Argument);
392     return(SPC_ERROR);
393   }
394
395   return(mempf1(channel, attach, pid));
396 }
397
398 /*----------------------------------------------------------------------+*/
399 int
400 XeSPCDetach(SPC_Channel_Ptr channel)
401 /*----------------------------------------------------------------------+*/
402 {
403   if(channel == SPC_ERROR) {
404     SPC_Error(SPC_Bad_Argument);
405     return(SPC_ERROR);
406   }
407   
408   channel->pid = 0;
409   channel->IOMode &= ~SPCIO_ACTIVE;
410
411   return XeSPCReset(channel);
412 }
413   
414
415  
416 /*
417  ***
418  *** "Composite" functions -- Those which are defined in terms of the
419  *** above primitives.  One assumption is that the above primitives check
420  *** their arguments, so the composite functions need only check any
421  *** additional arguments.
422  ***
423 */
424
425 /*
426  **
427  ** Start with subprocess creation routines
428  **
429 */
430
431 /*----------------------------------------------------------------------+*/
432 int
433 XeSPCSpawn(XeString pathname,
434            XeString context_dir,
435            XeString *argv,
436            XeString *envp,
437            SPC_Channel_Ptr channel)
438 /*----------------------------------------------------------------------+*/
439 {
440
441   if(channel==SPC_ERROR) {
442     SPC_Error(SPC_Bad_Argument);
443     return(SPC_ERROR);
444   }
445   
446   /* Assign the command arguments to this channel and attempt to Execute */
447     
448   if(channel->envp) {
449     SPC_Free_Envp(channel->envp);
450     channel->envp=NULL;
451   }
452   if(channel->argv && IS_SPCIO_DEALLOC_ARGV(channel->IOMode)) {
453     SPC_Free_Envp(channel->argv);
454     channel->IOMode &= ~SPCIO_DEALLOC_ARGV;
455     channel->argv=NULL;
456   }
457   
458   channel->context_dir=context_dir;
459   channel->argv = argv;
460   channel->path = pathname;
461
462   channel->envp=SPC_Create_Default_Envp(channel->envp);
463   channel->envp=SPC_Merge_Envp(channel->envp, envp);
464   channel->envp=SPC_Fixup_Environment(channel->envp, channel);
465
466   if(IS_SPCIO_SYSTEM(channel->IOMode))
467     if(SPC_MakeSystemCommand(channel)==SPC_ERROR)
468       return(SPC_ERROR);
469   
470   /* Execute the process (XeSPCExecuteProcess will check arguments */
471   
472   return(XeSPCExecuteProcess(channel));
473 }
474
475 /*----------------------------------------------------------------------+*/
476 SPC_Channel_Ptr XeSPCOpenAndSpawn(XeString hostname,
477                                   int iomode,
478                                   XeString pathname,
479                                   XeString context_dir,
480                                   XeString *argv,
481                                   XeString *envp)
482 /*----------------------------------------------------------------------+*/
483 {
484   /* This simply wraps together the two steps: Open and Spawn */
485   SPC_Channel_Ptr channel;
486
487   channel = XeSPCOpen(hostname, iomode);
488   if(channel==SPC_ERROR)
489     return(SPC_ERROR);
490   
491   if (XeSPCSpawn(pathname, context_dir, argv, envp, channel)!=SPC_ERROR)
492     return(channel);
493
494   /* Close the channel and return SPC_ERROR */
495   XeSPCClose(channel);
496   return(SPC_ERROR);
497   
498 }
499
500 /*
501  **
502  ** Signalling routines
503  **
504 */
505
506 /*----------------------------------------------------------------------+*/
507 void
508 XeSPCKillProcesses(int wait)
509 /*----------------------------------------------------------------------+*/
510 {
511   /* Attempt to KILL all the sub-process that we know of */
512   SPC_Channel_Ptr spc;
513
514   _DtSvcProcessLock();
515   for (spc = spc_activation_list; spc != (SPC_Channel_Ptr) NULL; spc = spc->next)
516     XeSPCKillProcess(spc, wait);
517   _DtSvcProcessUnlock();
518 }
519
520 /*----------------------------------------------------------------------+*/
521 int
522 XeSPCKillProcess(SPC_Channel_Ptr channel,
523                  int wait)
524 /*----------------------------------------------------------------------+*/
525 {
526   /* Attempt to KILL the sub-process (should we nullify the pid?) */
527   int result;
528
529   if(!channel)
530     return(FALSE);
531
532   if(IS_ACTIVE(channel)) {
533     result = XeSPCSignalProcess(channel, SIGKILL);
534     if(result==SPC_ERROR)
535       return(SPC_ERROR);
536     if (wait || IS_SPCIO_SYNC_TERM(channel->IOMode))
537       SPC_Wait_For_Termination(channel);
538     return result;
539   } else
540     return(TRUE);
541 }
542
543 /*----------------------------------------------------------------------+*/
544 int
545 XeSPCInterruptProcess(SPC_Channel_Ptr channel)
546 /*----------------------------------------------------------------------+*/
547 {
548   /* Attempt to INTerrupt the sub-process */
549   
550   return(XeSPCSignalProcess(channel, SIGINT));
551 }
552
553 /*
554  **
555  ** Process information routines.
556  **
557 */
558
559 /*----------------------------------------------------------------------+*/
560 XeString XeSPCGetDevice(SPC_Channel_Ptr channel,
561                               int connector, 
562                               int side)
563 /*----------------------------------------------------------------------+*/
564 {
565   if(!channel) {
566     SPC_Error(SPC_Bad_Argument);
567     return(SPC_ERROR);
568   }
569   
570   /* Return the device name which corresponds to the side of a channel */
571   if (connector>=STDIN && connector<=STDERR) {
572     if (side == MASTER_SIDE)
573       return(channel->wires[connector]->master_name);
574     if (side == SLAVE_SIDE)
575       return(channel->wires[connector]->slave_name);
576   }
577   
578   /* For no channel or incorrect side, return SPC_ERROR */
579   
580   SPC_Error(SPC_Bad_Argument);
581   return(SPC_ERROR);
582 }
583
584 /*----------------------------------------------------------------------+*/
585 int
586 XeSPCGetProcessStatus(SPC_Channel_Ptr channel,
587                       int *type, 
588                       int *cause)
589 /*----------------------------------------------------------------------+*/
590 {
591   /* Fill in the type and cause of a process termination */
592   int high, low;
593
594   if(!channel || !type || !cause) {
595     SPC_Error(SPC_Bad_Argument);
596     return(SPC_ERROR);
597   }
598     
599   low = channel->status & WAIT_STATUS_MASK;
600   high = (channel->status >> 8) & WAIT_STATUS_MASK;
601
602   *cause = high;
603
604   switch (low) {
605
606   case IS_WAIT_STATUS_STOPPED:
607     *type = SPC_PROCESS_STOPPED;
608     break;
609
610   case IS_WAIT_STATUS_EXITED:
611     *type = SPC_PROCESS_EXITED;
612     break;
613
614   default:
615     if (!*cause) {
616       *cause = low;
617       *type = SPC_PROCESS_SIGNALLED;
618     }
619     break;
620
621   }                             /* End switch on status */
622
623   /* When a process is still active return FALSE */
624   return(TRUE);
625 }
626
627 /*----------------------------------------------------------------------+*/
628 int
629 XeSPCGetPID(SPC_Channel_Ptr channel)
630 /*----------------------------------------------------------------------+*/
631 {
632
633   if(!channel) {
634     SPC_Error(SPC_Bad_Argument);
635     return(SPC_ERROR);
636   }
637   return (channel->pid);
638 }
639
640 /*----------------------------------------------------------------------+*/
641 int XeSPCGetLogfile(SPC_Channel_Ptr channel,
642                     XeString *host, 
643                     XeString *file)
644 /*----------------------------------------------------------------------+*/
645 {
646
647   if(!channel || !IS_SPCIO_USE_LOGFILE(channel->IOMode)) {
648     SPC_Error(SPC_Bad_Argument);
649     return(SPC_ERROR);
650   }
651   *file=channel->logfile;
652   _DtSvcProcessLock();
653   if(IS_REMOTE(channel))
654     *host=channel->connection->hostname;
655   else
656     *host= official_hostname;
657   _DtSvcProcessUnlock();
658   return(TRUE);
659   
660 }
661
662 /*----------------------------------------------------------------------+*/
663 int XeSPCRemoveLogfile(SPC_Channel_Ptr channel)
664 /*----------------------------------------------------------------------+*/
665
666
667   if(!channel) {
668     SPC_Error(SPC_Bad_Argument);
669     return(SPC_ERROR);
670   }
671   
672   return(mempf0(channel, remove_logfile));
673 }
674
675 /*
676  **
677  ** Synchronous termination
678  **
679 */
680
681 #define SINGLE_PROT_DATA(req, channel, connector)  \
682   if(!channel->queued_remote_data)                 \
683     channel->queued_remote_data=Xe_make_queue(FALSE); \
684   Xe_push_queue(channel->queued_remote_data, req);    \
685   if(channel->Input_Handler) {                     \
686     SPC_Input_Handler(channel, connector);         \
687   }
688
689 /*
690  **
691  ** SPC_Process_Single_Prot_Request will return TRUE if it is okay
692  ** for the caller to free the protocol request.
693  **
694 */
695
696 /*----------------------------------------------------------------------+*/
697 int
698 SPC_Process_Single_Prot_Request(protocol_request_ptr req, SPC_Channel_Ptr channel)
699 /*----------------------------------------------------------------------+*/
700 {
701
702   switch(req->request_type) {
703     
704   case APPLICATION_DIED:
705     
706     READ_APPLICATION_DIED(req->dataptr, channel->status);
707     SPC_Channel_Terminated(channel);
708     return(TRUE);
709     
710   case APPLICATION_STDOUT:
711     SINGLE_PROT_DATA(req, channel, STDOUT);
712     return(FALSE);
713     
714   case APPLICATION_STDERR:
715     SINGLE_PROT_DATA(req, channel, STDERR);
716     return(FALSE);
717       
718   default:
719     SPC_Error(SPC_Internal_Error);
720     return(SPC_ERROR);
721   }
722 }    
723   
724 /*----------------------------------------------------------------------+*/
725 SPC_Channel_Ptr XeSPCHandleTerminator(int fd)
726 /*----------------------------------------------------------------------+*/
727 {
728   SPC_Connection_Ptr connection;
729   SPC_Channel_Ptr channel;
730   protocol_request_ptr prot;
731   XeQueue connection_queue;
732   
733   if(!(connection=SPC_Lookup_Connection_Fd(fd))) {
734     SPC_Error(SPC_Bad_Argument);
735     return(SPC_ERROR);
736   }
737   
738   if(!(prot=SPC_Read_Protocol(connection))) {
739     return(SPC_ERROR);
740   }
741
742   connection_queue=connection->queued_remote_data;
743   Xe_push_queue(connection_queue, prot);
744
745   while((prot=(protocol_request_ptr)Xe_pop_queue(connection_queue))) {
746     
747     channel=prot->channel;
748
749     if(channel) {
750       channel->IOMode |= SPCIO_DELAY_CLOSE;
751       
752       if(SPC_Process_Single_Prot_Request(prot, channel))
753         SPC_Free_Protocol_Ptr(prot);
754       
755       channel->IOMode &= ~SPCIO_DELAY_CLOSE;
756       if(IS_SPCIO_DO_CLOSE(channel->IOMode)) {
757         XeSPCClose(channel);
758         channel = NULL;
759       }
760     }
761     
762   }
763   
764   return(channel);
765   
766 }
767
768 /*
769  **
770  ** Use this call to get the file descriptor for
771  ** Synchronous termination.
772  **
773 */
774
775 /*----------------------------------------------------------------------+*/
776 int
777 XeSPCGetChannelSyncFd(SPC_Channel_Ptr channel)
778 /*----------------------------------------------------------------------+*/
779 {
780
781   SPC_Connection_Ptr conn;
782
783   if(channel==SPC_ERROR) {
784     SPC_Error(SPC_Bad_Argument);
785     return(SPC_ERROR);
786   }
787   
788   conn=SPC_Channel_Terminator_Connection(channel);
789   return(conn->sid);
790   
791 }
792
793 /*
794  ***
795  *** Error Handling routines.
796  ***
797 */
798
799 /*----------------------------------------------------------------------+*/
800 SPCError *XeSPCLookupError(int errnum)
801 /*----------------------------------------------------------------------+*/
802 {
803   if(errnum<SPC_Min_Error || errnum > SPC_Max_Error) {
804     SPC_Error(SPC_Bad_Argument);
805     return(SPC_ERROR); 
806   }
807    
808   return(SPC_Lookup_Error(errnum));
809 }
810
811 /*
812  ***
813  *** Temporarily shutdown input handlers
814  ***
815 */
816
817 /*----------------------------------------------------------------------+*/
818 void XeSPCShutdownCallbacks(void)
819 /*----------------------------------------------------------------------+*/
820 {
821   SPC_Channel_Ptr channel;
822   SPC_Connection_Ptr conn;
823   Wire *wirelist;
824
825   _DtSvcProcessLock();
826   channel=spc_activation_list;
827   conn=connection_list;
828
829   while(channel) {
830     for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
831       if(wirelist->read_toolkit_id   != -1)
832         SPC_XtRemoveInput(&wirelist->read_toolkit_id, SPC_Input);
833       if(wirelist->except_toolkit_id != -1)
834         SPC_XtRemoveInput(&wirelist->except_toolkit_id, SPC_Exception);
835     }
836     channel=channel->next;
837   }
838
839   while(conn) {
840     if(conn->termination_id != -1)
841       SPC_XtRemoveInput(&conn->termination_id, SPC_Terminator);
842     conn=conn->next;
843   }
844   _DtSvcProcessUnlock();
845 }
846
847 /*----------------------------------------------------------------------+*/
848 void XeSPCRestartCallbacks(void)
849 /*----------------------------------------------------------------------+*/
850 {
851   SPC_Channel_Ptr channel;
852
853   _DtSvcProcessLock();
854   channel=spc_activation_list;
855
856   while(channel) {
857     if(channel->Input_Handler)
858       XeSPCAddInput(channel, (SbInputHandlerProc)NULL, NULL);
859     if(channel->Terminate_Handler)
860       XeSPCRegisterTerminator(channel, NULL, NULL);
861     channel=channel->next;
862   }
863   _DtSvcProcessUnlock();
864 }
865
866 /*
867  ***
868  *** Okay, now for a non-SPC routine.  This one is dealing with setpgrp,
869  *** but it is here because it uses internal SPC routines.
870  ***
871 */
872
873 /*----------------------------------------------------------------------+*/
874 int
875 XeSetpgrp(int read_current_termio)
876 /*----------------------------------------------------------------------+*/
877 {
878
879   return(SPC_Setpgrp(read_current_termio));
880 }  
881
882 int XeSPCSendEOF(SPC_Channel_Ptr channel)
883 {
884   if(channel==SPC_ERROR) {
885     SPC_Error(SPC_Bad_Argument);
886     return(SPC_ERROR);
887   }
888   
889   return(mempf0(channel, send_eof));
890 }
891
892 int XeSPCSetTermio(SPC_Channel_Ptr channel, int connection, int side,
893                    struct termios *termio)
894 {
895   if(channel==SPC_ERROR || termio == NULL) {
896     SPC_Error(SPC_Bad_Argument);
897     return(SPC_ERROR);
898   }
899   
900   return(mempf3(channel, set_termio, connection, side, termio));
901 }
902