3bf96ab593ac684152ade13f378e20c71af53cf0
[oweals/cde.git] / cde / lib / DtSvc / DtEncap / spc-proto.c
1 /*
2  * $TOG: spc-proto.c /main/12 1999/10/14 16:00:27 mgreess $
3  * Language:     C
4  *
5  * (c) Copyright 1996 Digital Equipment Corporation.
6  * (c) Copyright 1989,1993,1994,1996 Hewlett-Packard Company.
7  * (c) Copyright 1993,1994,1996 International Business Machines Corp.
8  * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
9  * (c) Copyright 1993,1994,1996 Novell, Inc. 
10  * (c) Copyright 1996 FUJITSU LIMITED.
11  * (c) Copyright 1996 Hitachi.
12  */
13
14 #define __need_timeval
15 #define __need_all_errors
16
17 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
18 #include <errno.h>
19 #include <stdarg.h>
20 #include <sys/utsname.h>
21 #include <limits.h>
22
23 #define X_INCLUDE_PWD_H
24 #define XOS_USE_XT_LOCKING
25 #include <X11/Xos_r.h>
26
27 #include <SPC/spcP.h>
28
29 #include <bms/MemoryMgr.h>
30
31 #include <SPC/spc-proto.h>
32
33 #include <Tt/tt_c.h>
34 #include "DtSvcLock.h"
35
36 /* Externals */
37 /*************/
38
39 extern struct termios *XeTermioStruct;    /* In pty.c */
40
41 extern XeString *environ;
42 extern SPC_Channel_Ptr spc_activation_list;
43
44 /* Gobals */
45 /**********/
46
47 /* FILE *SPC_Print_Protocol=NULL; -- now in bmsglob.c */
48
49 SPC_Connection_Ptr connection_list = NULL;
50 protocol_request_ptr free_protocol_requests = NULL;
51
52 /* Forwards */
53 /************/
54
55 static int SPC_Send_Termios(protocol_request_ptr prot_request);
56 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
57                               protocol_request_ptr prot,
58                               char *path,
59                               char *dir,
60                               char **argv,
61                               char **envp);
62
63 /*----------------------------------------------------------------------+*/
64 buffered_data_ptr SPC_New_Buffered_Data_Ptr(void)
65 /*----------------------------------------------------------------------+*/
66 {
67   buffered_data_ptr bdata;
68
69   bdata=(buffered_data_ptr)XeMalloc(sizeof(buffered_data));
70   bdata->len = bdata->offset = 0;
71   return(bdata);
72 }
73
74
75 /*----------------------------------------------------------------------+*/
76 void SPC_Reset_Protocol_Ptr (protocol_request_ptr prot, 
77                              SPC_Channel_Ptr channel, 
78                              XeChar req, 
79                              int len)
80 /*----------------------------------------------------------------------+*/
81 {
82   buffered_data_ptr  dptr=prot->dataptr;
83   
84   dptr->len          = len;
85   dptr->offset       = 0;
86   prot->seqno        = 0;
87   prot->request_type = req;
88   prot->channel      = channel;
89   prot->next         = NULL;
90   memset(dptr->data, (XeChar)' ', REQUEST_HEADER_LENGTH);
91 }
92
93 /*----------------------------------------------------------------------+*/
94 protocol_request_ptr SPC_New_Protocol_Ptr (SPC_Channel_Ptr channel, 
95                                            XeChar req, 
96                                            int len)
97 /*----------------------------------------------------------------------+*/
98 {
99   protocol_request_ptr prot;
100
101   _DtSvcProcessLock();
102   if(free_protocol_requests) {
103     prot = free_protocol_requests;
104     free_protocol_requests = free_protocol_requests->next;
105   } else {
106     prot = (protocol_request_ptr)XeMalloc(sizeof(protocol_request));
107     prot->dataptr = SPC_New_Buffered_Data_Ptr();
108   }
109   SPC_Reset_Protocol_Ptr(prot, channel, req, len);
110   _DtSvcProcessUnlock();
111   return(prot);
112 }
113
114 /*----------------------------------------------------------------------+*/
115 void SPC_Free_Protocol_Ptr(protocol_request_ptr prot)
116 /*----------------------------------------------------------------------+*/
117 {
118   _DtSvcProcessLock();
119   prot->next = free_protocol_requests;
120   free_protocol_requests = prot;
121   _DtSvcProcessUnlock();
122 }
123
124
125 /*----------------------------------------------------------------------+*/
126 SPC_Channel_Ptr SPC_Lookup_Channel(int cid,
127                                    SPC_Connection_Ptr connection)
128 /*----------------------------------------------------------------------+*/
129 {
130   
131   SPC_Channel_Ptr spc;
132
133   if(!cid)
134     return(NULL);
135   
136   _DtSvcProcessLock();
137   for(spc=spc_activation_list; spc; spc=spc->next)
138     /* This test is here because:
139        a. Only remote channels have cid's
140        b. It is possible for multiple remote servers to have
141           the same cid (which is simply the address of the channel),
142           so we need to distinguish among remote channels, but
143        c. channels on the remote daemon have cid's, but a null connection.
144        */
145     if((spc->cid == cid) &&
146        (!spc->connection ||
147         (spc->connection == connection))) {
148         _DtSvcProcessUnlock();
149         return(spc);
150     }
151   
152   _DtSvcProcessUnlock();
153   return(NULL);
154 }
155
156 /*
157  * Connection management routines
158  */
159
160
161 /*----------------------------------------------------------------------+*/
162 SPC_Connection_Ptr SPC_Alloc_Connection(void)
163 /*----------------------------------------------------------------------+*/
164 {
165   SPC_Connection_Ptr conn;
166
167   _DtSvcProcessLock();
168   conn=(SPC_Connection_Ptr) XeMalloc(sizeof(SPC_Connection));
169   /* Zero the connection */
170   memset(conn, NULL, sizeof(SPC_Connection));
171   conn->queued_remote_data = Xe_make_queue(FALSE);
172   conn->termination_id = (-1);
173   /* Init the socket id to "-1" because "0" is a valid file descriptor. */
174   conn->sid = (-1);
175   _DtSvcProcessUnlock();
176   return(conn);
177 }
178
179
180 /*----------------------------------------------------------------------+*/
181 SPC_Connection_Ptr SPC_Lookup_Connection(XeString hostname)
182 /*----------------------------------------------------------------------+*/
183 {
184   /* Search for an existing connection to a server */
185   SPC_Connection_Ptr conn;
186
187   _DtSvcProcessLock();
188   for (conn = connection_list; conn != NULL; conn = conn->next) {
189
190     /* Look for a connection with the same hostname */
191       if (!strcmp(conn->hostname, hostname)) {
192           _DtSvcProcessUnlock();
193           return(conn);
194       }
195   }
196   
197   _DtSvcProcessUnlock();
198   return(FALSE);
199 }
200
201 /*----------------------------------------------------------------------+*/
202 SPC_Connection_Ptr SPC_Lookup_Connection_Fd(int fd)
203 /*----------------------------------------------------------------------+*/
204 {
205   /* Search for an existing connection to a server, using fd (file descriptor)
206    as a key */
207   SPC_Connection_Ptr conn;
208
209   _DtSvcProcessLock();
210   for (conn = connection_list; conn != NULL; conn = conn->next) {
211
212     /* Look for a connection with the same hostname */
213       if (conn->sid==fd) {
214           _DtSvcProcessUnlock();
215           return(conn);
216       }
217   }
218   
219   _DtSvcProcessUnlock();
220   return(FALSE);
221 }
222
223 /*----------------------------------------------------------------------+*/
224 SPC_Connection_Ptr SPC_Make_Connection(XeString hostname)
225 /*----------------------------------------------------------------------+*/
226 {
227   /* Search for a connection to hostname, create one if none exists */
228   
229   SPC_Connection_Ptr conn;
230
231   /* Searching for connected host maintains only one connection per remote */
232
233   if(hostname && (conn=SPC_Lookup_Connection(hostname)))
234     return(conn);
235   
236   /* Not found, so make one */
237   
238   if((conn = SPC_Alloc_Connection())==SPC_ERROR)
239     return(SPC_ERROR);
240
241   if(hostname)
242     strcpy(conn->hostname, hostname);
243   
244   SPC_Add_Connection(conn);
245   return(conn);
246 }
247
248 /*----------------------------------------------------------------------+*/
249 void SPC_Add_Connection(SPC_Connection_Ptr connection)
250 /*----------------------------------------------------------------------+*/
251 {
252   
253   /* Add a connection to the connection_list */
254   _DtSvcProcessLock();
255   connection->next = connection_list;
256   connection_list = connection;
257   _DtSvcProcessUnlock();
258 }
259
260 /*----------------------------------------------------------------------+*/
261 void SPC_Close_Connection(SPC_Connection_Ptr connection)
262 /*----------------------------------------------------------------------+*/
263 {
264   SPC_Channel_Ptr channel;
265   SPC_Channel_Ptr next;
266   SPC_Connection_Ptr trail, ptr;
267
268   /* We have to be careful here.  SPC_Input_Handler may call the users
269      termination handler, which in turn might close the channel, which
270      may deallocate the channel.  Therefore, we grab the next channel
271      from the list while we are still alive. */
272
273   _DtSvcProcessLock();
274   channel=spc_activation_list;
275   connection->connected = FALSE;
276   
277   while(channel) {
278     next=channel->next;
279     if(channel->connection == connection) {
280       if(!IS_SPCIO_DELAY_CLOSE(channel->IOMode))
281         SPC_Channel_Terminated(channel);
282       channel->connection = NULL;
283     }
284     channel=next;
285   }
286   
287   SPC_XtRemoveInput(&connection->termination_id, SPC_Terminator);
288
289   spc_close(connection->sid);
290   connection->sid = (-1);
291
292   if (connection->hostinfo)
293       XeFree(connection->hostinfo);
294
295   /* Remove the connection from the connection list */
296
297   if(connection_list == connection)
298     connection_list = connection->next;
299   else {
300     trail = connection_list;
301     while(trail) {
302       ptr = trail->next;
303       if(ptr == connection) {
304         trail->next = ptr->next;
305         break;
306       }
307       trail=ptr;
308     }
309     if(!trail) {
310       /* Here if no such connection found. */
311     }
312   }
313
314   free((char *)connection);
315   _DtSvcProcessUnlock();
316 }
317
318 /*
319  **
320  ** Read the specified number of characters, or die trying.
321  **
322 */
323
324 /*----------------------------------------------------------------------+*/
325 int SPC_Read_Chars(SPC_Connection_Ptr   connection,
326                    int                  request_len,
327                    XeString             charptr)
328 /*----------------------------------------------------------------------+*/
329 {
330
331   int numchars, numread;
332   int numtoread=request_len;
333   int sid=connection->sid;
334   
335   numread=0;
336
337   while(numread<request_len) {
338     do
339       numchars=read(sid, charptr, numtoread);
340     while(numchars == ERROR && errno == EINTR);
341     if(numchars == ERROR) {
342       XeString connection_hostname = CONNECTION_HOSTNAME(connection);
343       if(errno == ECONNRESET)
344         SPC_Error(SPC_Connection_Reset, connection_hostname);
345       else
346         SPC_Error(SPC_Reading, connection_hostname);
347       XeFree(connection_hostname);
348       return(SPC_ERROR);
349     }
350     if(numchars == 0) {
351       XeString connection_hostname = CONNECTION_HOSTNAME(connection);
352       SPC_Error(SPC_Connection_EOF, connection_hostname);
353       XeFree(connection_hostname);
354       return(SPC_ERROR);    /* Bad news, EOF on incoming channel */
355     }
356     charptr += numchars;
357     numread += numchars;
358     numtoread -= numchars;
359   }
360   *charptr=(XeChar)'\0';
361   return(numread);
362 }
363
364 /* Write len chars, or die trying */
365
366 /*----------------------------------------------------------------------+*/
367 int SPC_Write_Chars(int         fd,
368                     XeString    charptr,
369                     int         request_len)
370 /*----------------------------------------------------------------------+*/
371 {
372   int numchars, numwritten;
373   int numtowrite=request_len;
374   
375   numwritten=0;
376   
377   while(numwritten<request_len) {
378     do
379       numchars=write(fd, charptr, numtowrite);
380     while(numchars == ERROR && errno == EINTR);
381
382 #ifdef DEBUG
383     _DtSvcProcessLock();
384     if(SPC_Print_Protocol)
385       fprintf(SPC_Print_Protocol,
386               "SPC_Write_Chars -- wrote: %d of %d, expected: %d, errno: %d\n",
387               numchars, request_len, numtowrite, errno);
388     _DtSvcProcessUnlock();
389 #endif    
390        
391     if(numchars == ERROR)
392       return(ERROR);
393
394     charptr    += numchars;
395     numwritten += numchars;
396     numtowrite -= numchars;
397   }
398   return(numwritten);
399 }
400   
401
402 /*
403  **
404  ** Read a single protocol request from the passed channel.
405  **
406 */
407
408 /*----------------------------------------------------------------------+*/
409 protocol_request_ptr SPC_Read_Protocol(SPC_Connection_Ptr connection)
410 /*----------------------------------------------------------------------+*/
411 {
412   int                channel_id;
413   protocol_request_ptr prot;
414   buffered_data_ptr        dptr;
415   int len;
416
417   if(!connection->connected)
418     return(SPC_ERROR);
419   
420   if((prot=SPC_New_Protocol_Ptr(NULL, NULL, NULL))==SPC_ERROR) {
421     SPC_Close_Connection(connection);
422     return(SPC_ERROR);
423   }
424   
425   /* read header */
426
427   dptr=prot->dataptr;
428
429   len=SPC_Read_Chars(connection, REQUEST_HEADER_LENGTH, dptr->data);
430   if(len != REQUEST_HEADER_LENGTH) {
431     SPC_Close_Connection(connection);
432     SPC_Free_Protocol_Ptr(prot);
433     return(SPC_ERROR);
434   }
435   
436   /* we have the header.  Parse out the fields */
437   
438   READ_HEADER(dptr,
439               &channel_id, &prot->request_type, &dptr->len, &prot->seqno);
440   prot->channel=SPC_Lookup_Channel(channel_id, connection);
441   
442   /* read header */
443   
444   len=SPC_Read_Chars(connection, dptr->len, dptr->data+REQUEST_HEADER_LENGTH);
445   if(len != dptr->len) {
446     SPC_Close_Connection(connection);
447     SPC_Free_Protocol_Ptr(prot);
448     return(SPC_ERROR);
449   }
450
451   dptr->offset=REQUEST_HEADER_LENGTH;
452   return(prot);
453   
454 }
455
456 /*
457  **
458  ** Filter the connection for the desired type of protocol request.
459  ** If there is a protocol request of the desired type already queued,
460  ** return it.  If not, read a new one.  If we read requests destined
461  ** for another channel, or for our channel but not the correct
462  ** request type, queue it up.  If the deletep flag is TRUE, remove it
463  ** from the queue.
464  **
465 */
466
467 /*----------------------------------------------------------------------+*/
468 protocol_request_ptr  SPC_Filter_Connection(SPC_Connection_Ptr connection,
469                                             SPC_Channel_Ptr channel,
470                                             int reqtype, 
471                                             int deletep)
472 /*----------------------------------------------------------------------+*/
473 {
474   SPC_Connection_Ptr connptr=NULL;
475   SPC_Channel_Ptr conn_channel;
476   XeQueue   tmpqueue;
477   protocol_request_ptr retval;
478   int protreqtype;
479
480   /* check if there are any queued prot. requests.  If so,
481      check for their having the type we want */
482   
483   if(channel && (tmpqueue=channel->queued_remote_data)) {
484     tmpqueue=channel->queued_remote_data;
485     {
486       Xe_for_queue(protocol_request_ptr, retval, tmpqueue) {
487         /* found a queued packet.  Is it what we are looking for? */
488         if(retval->request_type == reqtype) {
489           /* yes. */
490           if(deletep)
491             Xe_delete_queue_element(channel->queued_remote_data, retval);
492           return(retval);
493         }
494       }
495     }
496   }
497   
498   /* No queued elements.  Read until we get the reply we
499      are looking for */
500   while(TRUE) {
501     if((retval=SPC_Read_Protocol(connection))==SPC_ERROR)
502       return(SPC_ERROR);
503
504     protreqtype=retval->request_type;
505     conn_channel=retval->channel;
506
507     if(protreqtype == ABORT) {
508       XeString connection_hostname = CONNECTION_HOSTNAME(connection);
509       SPC_Error(SPC_Protocol_Abort, connection_hostname);
510       XeFree (connection_hostname);
511       return(SPC_ERROR);
512     }
513
514     _DtSvcProcessLock();
515     if(protreqtype == SERVER_ERROR) {
516       READ_ERROR(retval->dataptr, XeSPCErrorNumber);
517       SPC_Error(XeSPCErrorNumber, XeString_NULL, 0);
518       _DtSvcProcessUnlock();
519       return(SPC_ERROR);
520     }
521     _DtSvcProcessUnlock();
522
523     if(!conn_channel)
524       return(retval);
525
526     if((conn_channel == channel) && (protreqtype == reqtype)) {
527       /* We found one that matches.  Check if we need to queue it up. */
528       if(!deletep)
529         Xe_push_queue(conn_channel->queued_remote_data, retval);
530       return(retval);
531     }
532     
533     /* No match.  Queue it up */
534     if(IS_SPCIO_SYNC_TERM(channel->IOMode))
535       Xe_push_queue(connection->queued_remote_data, retval);
536     else
537       Xe_push_queue(conn_channel->queued_remote_data, retval);
538     
539   }
540 }
541
542 /*----------------------------------------------------------------------+*/
543 void SPC_Flush_Queued_Data(SPC_Channel_Ptr channel)
544 /*----------------------------------------------------------------------+*/
545 {
546   XeQueue tmpqueue;
547   protocol_request_ptr prot;
548   
549   if(tmpqueue=channel->queued_remote_data) {
550     while(prot=(protocol_request_ptr)Xe_pop_queue(tmpqueue))
551       SPC_Free_Protocol_Ptr(prot);
552   }
553
554   if(channel->connection && (tmpqueue=channel->connection->queued_remote_data))
555     {
556       Xe_for_queue(protocol_request_ptr, prot, tmpqueue) {
557         if(prot->channel == channel) {
558           Xe_delete_queue_element(tmpqueue, prot);
559           SPC_Free_Protocol_Ptr(prot);
560         }
561       }
562     }
563 }
564
565 /*----------------------------------------------------------------------+*/
566 int SPC_Read_Remote_Data(SPC_Channel_Ptr channel,
567                          int connector,
568                          XeString client_buffer,
569                          int nbytes)
570 /*----------------------------------------------------------------------+*/
571 {
572   int ret_len;
573
574   SPC_Connection_Ptr connection=channel->connection;
575   protocol_request_ptr prot;
576   buffered_data_ptr    pdata;
577   int req_type=CONNECTOR_TO_PROT(connector);
578
579   prot=SPC_Filter_Connection(connection, channel, req_type, FALSE);
580   if(prot==SPC_ERROR)
581     return(SPC_ERROR);
582   
583   pdata=prot->dataptr;
584   
585   ret_len = min(nbytes, pdata->len);
586   
587   memcpy(client_buffer, pdata->data+pdata->offset, ret_len);
588   pdata->offset += ret_len;
589   pdata->len    -= ret_len;
590   if(pdata->len == 0) {
591     SPC_Filter_Connection(connection, channel, req_type, TRUE);
592     SPC_Free_Protocol_Ptr(prot);
593   }
594
595   return(ret_len);
596 }
597
598 /* Dump out a protocol request */
599
600 /*----------------------------------------------------------------------+*/
601 int print_protocol_request(XeString name, protocol_request_ptr proto)
602 /*----------------------------------------------------------------------+*/
603 {
604   buffered_data_ptr dptr = proto->dataptr;
605
606   _DtSvcProcessLock();
607   if(!SPC_Print_Protocol) {
608     _DtSvcProcessUnlock();
609     return FALSE;
610   }
611
612   dptr->data[dptr->offset+dptr->len]=0;
613   
614   fprintf(SPC_Print_Protocol,
615           "%s channel: %x, request: %d, length: %d, seq: %d data: %s\n",
616           name, proto->channel, proto->request_type, dptr->len, proto->seqno,
617           dptr->data+dptr->offset);
618
619   fflush(SPC_Print_Protocol);
620
621   _DtSvcProcessUnlock();
622   return TRUE;
623 }
624   
625 /*
626  * Write a protocol request to the given channel
627  *
628 */
629
630 int current_sequence_number=1;
631
632 /*----------------------------------------------------------------------+*/
633 int SPC_Write_Protocol_Request (SPC_Connection_Ptr connection, 
634                                 SPC_Channel_Ptr channel, 
635                                 int request, 
636                                 ...)
637 /*----------------------------------------------------------------------+*/
638 {
639   va_list               ap;
640   protocol_request_ptr  prot_request;
641   buffered_data_ptr     pdata;
642   int                   reply_expected;
643   XeString              prot_name=NULL;
644   
645   prot_request=SPC_New_Protocol_Ptr(channel, request, 0);
646   pdata=prot_request->dataptr;
647   _DtSvcProcessLock();
648   prot_request->seqno = current_sequence_number++;
649   _DtSvcProcessUnlock();
650
651   /* We are overloading the "channel" field.  We put the cid rather  */
652   /* than the actual channel pointer in when we pass it to the other */
653   /* side of the connection.                                         */
654   prot_request->channel=(SPC_Channel_Ptr)(channel ? channel->cid : 0);
655   
656   switch (request) {
657
658   case ABORT:
659     pdata->len=WRITE_ABORT(pdata, 0);
660     prot_name=(XeString)"  <-- ABORT";
661     break;
662     
663  case REGISTER:
664     {
665     XeString username;
666     XeString passwd;
667     XeString proto_ver;
668     XeString hostinfo;
669
670     va_start(ap, request);
671     username=va_arg(ap, XeString );    
672     passwd=va_arg(ap, XeString );
673     proto_ver=va_arg(ap, XeString );
674     hostinfo=va_arg(ap, XeString );
675     va_end(ap);
676     pdata->len=WRITE_REGISTER(pdata, username, passwd, proto_ver, hostinfo);
677     prot_name=(XeString)"  <-- REGISTER";
678     break;
679     }
680     
681     
682   case UNREGISTER:
683     prot_name=(XeString)"  <-- UNREGISTER";
684     break;
685     
686   case CHANNEL_OPEN:
687     va_start(ap, request);
688     pdata->len=WRITE_OPEN(pdata, va_arg(ap, int));
689     va_end(ap);
690     prot_name=(XeString)"  <-- CHANNEL_OPEN";
691     break;
692
693   case CHANNEL_CLOSE:
694     /* This is correct.  This protocol request takes no args */
695     prot_name=(XeString)"  <-- CHANNEL_CLOSE";
696     break;
697     
698   case CHANNEL_RESET:
699     /* This one, either */
700     prot_name=(XeString)"  <-- CHANNEL_RESET";
701     break;
702     
703   case CHANNEL_ATTACH:
704     prot_name=(XeString)"  <-- CHANNEL_ATTACH";
705     va_start(ap, request);
706     pdata->len=WRITE_ATTACH(pdata, va_arg(ap, int));
707     va_end(ap);
708     break;
709     
710   case APPLICATION_SPAWN:
711     {
712     XeString path;
713     XeString dir;
714     XeString *argv;
715     XeString *envp;
716     
717     va_start(ap, request);
718
719     /* It is left as an exercise to the reader to figure out
720        what would happen if we didn't use these temp. variables
721        and instead used the va_arg macros directly in the
722        WRITE_APPLICATION_SPAWN... */
723     
724     path=va_arg(ap, XeString );
725     dir =va_arg(ap, XeString );
726     argv=va_arg(ap, XeString *);
727     envp=va_arg(ap, XeString *);
728     va_end(ap);
729     pdata->len=WRITE_APPLICATION_SPAWN(pdata, path, dir, argv, envp);
730     if(pdata->len == SPC_ERROR)
731       return(SPC_ERROR);
732     prot_name=(XeString)"  <-- APPLICATION_SPAWN";
733     break;
734     }
735     
736   case APPLICATION_SIGNAL:
737     {
738         if (connection->protocol_version >= 2) 
739         {
740             XeString signame;
741             
742             va_start(ap, request);
743             signame = va_arg(ap, XeString);
744             va_end(ap);
745             
746             pdata->len=WRITE_STRING(pdata, signame);
747         }
748         else
749         {
750             int      sig;
751             
752             va_start(ap, request);
753             sig = va_arg(ap, int);
754             va_end(ap);
755
756             pdata->len=WRITE_INT(pdata, sig);
757         }
758         
759         prot_name=(XeString)"  <-- APPLICATION_SIGNAL";
760         break;
761     }
762     
763   case APPLICATION_DIED:
764     va_start(ap, request);
765     pdata->len=WRITE_APPLICATION_DIED(pdata, va_arg(ap, int));
766     va_end(ap);
767     prot_name=(XeString)"  <-- APPLICATION_DIED";
768     break;
769
770   case APPLICATION_DATA:
771     prot_name=(XeString)"  <-- APPLICATION_DATA";
772     
773   case APPLICATION_STDOUT:
774     if(!prot_name)
775       prot_name=(XeString)"  <-- APPLICATION_STDOUT";
776     
777   case APPLICATION_STDERR:
778     {
779     int      buflen;
780     XeString buffer;
781     
782     if(!prot_name)
783       prot_name=(XeString)"  <-- APPLICATION_STDERR";
784     
785     va_start(ap, request);
786     buffer=va_arg(ap, XeString );
787     buflen=va_arg(ap, int);
788     va_end(ap);
789
790     pdata->len=WRITE_APP_DATA(pdata, buffer, buflen);
791
792     break;
793     }
794
795   case SERVER_ERROR:
796     va_start(ap, request);
797     pdata->len=WRITE_ERROR(pdata, va_arg(ap, int));
798     va_end(ap);
799     prot_name=(XeString)"  <-- SERVER_ERROR";
800     break;
801     
802   case REPLY:
803     {
804     int replyval, errval;
805     
806     va_start(ap, request);
807     prot_request->seqno=va_arg(ap, int);
808     replyval=va_arg(ap, int);
809     errval=va_arg(ap, int);
810     va_end(ap);
811     pdata->len=WRITE_REPLY(pdata, replyval, errval);
812     prot_name=(XeString)"  <-- REPLY";
813     break;
814     }
815
816   case DEVICE_REPLY:
817     { 
818     XeString m0;
819     XeString s0;
820     XeString m1;
821     XeString s1;
822     XeString m2;
823     XeString s2;
824
825     va_start(ap, request);
826     m0=va_arg(ap, XeString );
827     s0=va_arg(ap, XeString );
828     m1=va_arg(ap, XeString );
829     s1=va_arg(ap, XeString );
830     m2=va_arg(ap, XeString );
831     s2=va_arg(ap, XeString );
832     va_end(ap);
833     pdata->len=WRITE_DEVICE_REPLY(pdata, m0, s0, m1, s1, m2, s2);
834     prot_name=(XeString)"  <-- DEVICE_REPLY";
835     break;
836     }
837     
838   case QUERY_DEVICES:
839     prot_name=(XeString)"  <-- QUERY_DEVICES";
840     break;
841
842  case LOGFILE_REPLY:
843     {
844     XeString fname;
845     XeString proto_ver;
846     XeString hostinfo;
847
848     va_start(ap, request);
849     fname=va_arg(ap, XeString );
850     proto_ver=va_arg(ap, XeString );
851     hostinfo=va_arg(ap, XeString );
852     va_end(ap);
853     pdata->len=WRITE_LOGFILE_REPLY(pdata, fname, proto_ver, hostinfo);
854     prot_name=(XeString)"  <-- LOGFILE_REPLY";
855     break;
856     }
857     
858   case QUERY_LOGFILE:
859     prot_name=(XeString)"  <-- QUERY_LOGFILE";
860     break;
861
862   case DELETE_LOGFILE:
863     prot_name=(XeString)"  <-- DELETE_LOGFILE";
864     break;
865
866   case SERVER_DEBUG:
867     va_start(ap, request);
868     pdata->len=WRITE_DEBUG(pdata, va_arg(ap, XeString));
869     va_end(ap);
870     prot_name=(XeString)"  <-- SERVER_DEBUG";
871     break;
872
873   case ENVIRON_RESET:
874     return(SPC_Send_Environ(connection, prot_request));
875
876   /* We used to send the hp-ux version of a termio struct */
877   /* This is non-portable, so we don't do it anymore.     */
878
879   case RESET_TERMIOS:
880     pdata->len=SPC_Send_Termios(prot_request);
881     prot_name=(XeString)"  <-- RESET_TERMIOS";
882     break;
883
884   /* B.00 (protocol version 3) requests */
885     
886   case CHANNEL_SEND_EOF:
887
888     if(connection->protocol_version < 3) {
889       SPC_Error(SPC_Protocol_Version_Error,
890                 3, channel->connection->protocol_version);
891       return(SPC_ERROR);
892     }
893   
894     prot_name = (XeString)"  <-- CHANNEL_SEND_EOF";
895     break;
896
897   case CHANNEL_TERMIOS:
898
899     if(connection->protocol_version < 3) {
900       SPC_Error(SPC_Protocol_Version_Error,
901                 3, channel->connection->protocol_version);
902       return(SPC_ERROR);
903     }
904   
905     {
906       int connector, side;
907       struct termios *termios_ptr;
908       char *buffer;
909
910       va_start(ap, request);
911
912       connector   = va_arg(ap, int);
913       side        = va_arg(ap, int);
914       termios_ptr = va_arg(ap, struct termios *);
915       va_end(ap);
916
917       buffer = SPC_Decode_Termios(termios_ptr);
918       pdata->len=WRITE_TERMIOS(pdata, connector, side, buffer);
919       prot_name=(XeString)"  <-- CHANNEL_TERMIOS";
920       break;
921     }
922
923   case APP_B00_SPAWN:
924     if(connection->protocol_version < 3) {
925       SPC_Error(SPC_Protocol_Version_Error,
926                 3, channel->connection->protocol_version);
927       return(SPC_ERROR);
928     }
929
930     {
931     XeString path;
932     XeString dir;
933     XeString *argv;
934     XeString *envp;
935     int retval;
936     
937     va_start(ap, request);
938
939     /* It is left as an exercise to the reader to figure out
940        what would happen if we didn't use these temp. variables
941        and instead used the va_arg macros directly in the
942        WRITE_APPLICATION_SPAWN... */
943     
944     path=va_arg(ap, XeString );
945     dir =va_arg(ap, XeString );
946     argv=va_arg(ap, XeString *);
947     envp=va_arg(ap, XeString *);
948     va_end(ap);
949
950     retval =
951       SPC_Send_B00_Spawn(connection, prot_request, path, dir, argv, envp);
952     return(retval);
953     }
954     
955   }
956
957   reply_expected=
958     SPC_Write_Single_Prot_Request(connection, prot_name, prot_request);
959     
960   SPC_Free_Protocol_Ptr(prot_request);
961   return(reply_expected);
962 }
963
964
965 /*----------------------------------------------------------------------+*/
966 int SPC_Write_Single_Prot_Request(SPC_Connection_Ptr connection,
967                                   XeString name,
968                                   protocol_request_ptr prot)
969 /*----------------------------------------------------------------------+*/
970 {
971   int reply_expected, length;
972   buffered_data_ptr   pdata=prot->dataptr;
973
974   if(!connection->connected)
975     return(SPC_ERROR);
976   
977   reply_expected=
978     REPLY_EXPECTED(prot->request_type, prot->seqno);
979   length=WRITE_HEADER(pdata, prot->channel,
980                       prot->request_type,
981                       pdata->len,
982                       prot->seqno);
983   pdata->data[length]=(XeChar)' ';
984   
985   length=pdata->len+REQUEST_HEADER_LENGTH;
986   if(SPC_Write_Chars(connection->sid, pdata->data, length) == ERROR) {
987     XeString connection_hostname = CONNECTION_HOSTNAME(connection);
988     SPC_Close_Connection(connection);
989     SPC_Error(SPC_Write_Prot, connection_hostname);
990     XeFree(connection_hostname);
991     reply_expected = (SPC_ERROR);
992   }
993   
994   pdata->offset=REQUEST_HEADER_LENGTH;
995   print_protocol_request(name, prot);
996
997   return(reply_expected);
998 }
999
1000 /*----------------------------------------------------------------------+*/
1001 int SPC_Waitfor_Reply(SPC_Connection_Ptr connection,
1002                       SPC_Channel_Ptr channel,
1003                       int seqno)
1004 /*----------------------------------------------------------------------+*/
1005 {
1006
1007   protocol_request_ptr prot;
1008   int retval, errval;
1009   int thisseq;
1010   
1011   if(seqno == NO_REPLY_VAL)
1012     return(TRUE);
1013
1014   if(seqno==SPC_ERROR)
1015     return(SPC_ERROR);
1016   
1017   prot=SPC_Filter_Connection(connection, channel, REPLY, TRUE);
1018
1019   if(prot==SPC_ERROR)
1020     return(SPC_ERROR);
1021
1022   thisseq = prot->seqno;
1023   READ_REPLY(prot->dataptr, retval, errval);
1024
1025   SPC_Free_Protocol_Ptr(prot);
1026   
1027   if(thisseq != seqno) {
1028     SPC_Error(SPC_Unexpected_Reply);
1029     return(SPC_ERROR);
1030   }
1031   
1032   if(retval<0) {
1033     errno=errval;
1034     retval = -retval;
1035     if(retval != SPC_Protocol_Abort) {
1036       if (retval == SPC_Cannot_Create_Netfilename)
1037          SPC_Error(retval, channel->context_dir, connection->hostname);
1038       else if (retval == SPC_Cannot_Exec)
1039          SPC_Error(retval, channel->path, 0);
1040       else if (retval == SPC_cannot_Chdir)
1041          SPC_Error(retval, channel->context_dir, 0);
1042       else
1043          SPC_Error(retval, XeString_NULL, 0);
1044     }
1045     return(SPC_ERROR);
1046   }
1047   return(retval);
1048 }
1049       
1050
1051 /*----------------------------------------------------------------------+*/
1052 int SPC_Dispatch_Protocol(protocol_request_ptr proto,
1053                           protocol_request_handler *table)
1054 /*----------------------------------------------------------------------+*/
1055 {
1056   int req_type;
1057   
1058   if(!proto)
1059     return(FALSE);
1060   req_type=proto->request_type;
1061   
1062   if(req_type<0 || req_type>NREQS)
1063     return(FALSE);
1064
1065   return((* table[req_type])(proto));
1066 }
1067
1068 /*----------------------------------------------------------------------+*/
1069 int SPC_Write_Reply(SPC_Connection_Ptr conn,
1070                     protocol_request_ptr proto,
1071                     int retval,
1072                     int errval)
1073 /*----------------------------------------------------------------------+*/
1074 {
1075   _DtSvcProcessLock();
1076   if(retval==ERROR)
1077     retval=(-XeSPCErrorNumber);
1078   _DtSvcProcessUnlock();
1079
1080   return(SPC_Write_Protocol_Request(conn, proto->channel, REPLY,
1081                                     proto->seqno, retval, errval));
1082 }
1083
1084 /*
1085  **
1086  ** Send the current environment out to the world.
1087  **
1088 */
1089
1090 #define valid_str(x) (((x) != NULL) && (*(x) != 0))
1091 #define NULL_STR     "\001\001\001"
1092 #define EMPTY_STR    "\001\002\003"
1093
1094 int SPC_Send_Multi_Packet(SPC_Connection_Ptr connection,
1095                           protocol_request_ptr prot,
1096                           char **str_vect,
1097                           int num_str,
1098                           int req,
1099                           XeString name,
1100                           int errid)
1101 {
1102   int counter, tmp_len;
1103   int bytes_left, numbytes;
1104   XeString buf;
1105   int reply_seqno;
1106   int this_seqno;
1107   int valid_ep = 0;
1108   char *this_str;
1109
1110   _DtSvcProcessLock();
1111   this_seqno=current_sequence_number;
1112   numbytes=WRITE_ENVIRON_RESET(prot->dataptr, num_str);
1113   bytes_left=SPC_BUFSIZ-numbytes;
1114   buf=(PDRP(prot->dataptr) + numbytes);
1115   reply_seqno=prot->seqno;
1116   
1117   for(counter=0; counter<num_str; counter++) {
1118     this_str = str_vect[counter];
1119     
1120     if(this_str == NULL)
1121       this_str = NULL_STR;
1122     if(*this_str == NULL)
1123       this_str = EMPTY_STR;
1124     
1125     tmp_len=strlen(this_str)+1;         /* Room for NULL char */
1126     if((bytes_left-tmp_len) < 1) {
1127       *buf=NULL;
1128       prot->dataptr->len=numbytes+1;
1129       SPC_Write_Single_Prot_Request(connection, name, prot);
1130       SPC_Free_Protocol_Ptr(prot);
1131       prot=SPC_New_Protocol_Ptr(0, req, 0);
1132       prot->seqno=current_sequence_number++;
1133       numbytes=0;
1134       bytes_left=SPC_BUFSIZ;
1135       buf=(PDRP(prot->dataptr) + numbytes);
1136     }
1137     
1138     if(tmp_len>SPC_BUFSIZ-1) {
1139       SPC_Error(errid,
1140                 this_str,
1141                 SPC_BUFSIZ-1);
1142       SPC_Free_Protocol_Ptr(prot);
1143       if(this_seqno != current_sequence_number)
1144         SPC_Write_Protocol_Request(connection, NULL, ABORT);
1145       _DtSvcProcessUnlock();
1146       return(reply_seqno);
1147     }
1148
1149     strncpy(buf, this_str, tmp_len);
1150     bytes_left -= tmp_len;
1151     numbytes   += tmp_len;
1152     buf        += tmp_len;
1153   }
1154   
1155   if(numbytes) {
1156     *buf=NULL;
1157     prot->dataptr->len=numbytes+1;
1158     SPC_Write_Single_Prot_Request(connection, (XeString)"  <-- ENVIRON_RESET", prot);
1159     SPC_Free_Protocol_Ptr(prot);
1160   }
1161
1162   _DtSvcProcessUnlock();
1163   return(reply_seqno);
1164   
1165 }
1166
1167 char **SPC_Get_Multi_Packet(SPC_Connection_Ptr connection,
1168                             protocol_request_ptr prot,
1169                             char **out,
1170                             int *outlen,
1171                             int request,
1172                             XeString name)
1173
1174 {
1175   int num_vars, i, len;
1176   XeString bufptr;
1177   protocol_request_ptr localprot = NULL;
1178
1179   print_protocol_request(name, prot);
1180   READ_ENVIRON_RESET(prot->dataptr, num_vars);
1181   bufptr=strchr(PDRP(prot->dataptr), Space)+1;
1182   if(out == NULL)
1183     out = (char **)malloc((num_vars+1) * sizeof(char **));
1184   
1185   for(i=0; i<num_vars; i++) {
1186     len=strlen(bufptr);
1187     if(len==0) {
1188       if(localprot)
1189         SPC_Free_Protocol_Ptr(localprot);
1190       prot=SPC_Filter_Connection(connection, NULL, request, TRUE);
1191       if(prot==SPC_ERROR)
1192         return(SPC_ERROR);
1193       print_protocol_request(name, prot);
1194       localprot=prot;
1195       bufptr=PDRP(prot->dataptr);
1196       len=strlen(bufptr);
1197     }
1198     if(strcmp(bufptr, NULL_STR) == 0)
1199       out[i] = NULL;
1200     else {
1201       if(strcmp(bufptr, EMPTY_STR) == 0)
1202         out[i] = strdup("");
1203       else
1204         out[i] = strdup(bufptr);
1205     }
1206     bufptr += (len+1);
1207   }
1208   if(localprot)
1209     SPC_Free_Protocol_Ptr(localprot);
1210
1211   *outlen = num_vars;
1212   out[num_vars] = NULL;
1213   
1214   return(out);
1215 }
1216  
1217 /*----------------------------------------------------------------------+*/
1218 int SPC_Send_Environ(SPC_Connection_Ptr connection,
1219                      protocol_request_ptr prot)
1220 /*----------------------------------------------------------------------+*/
1221 {
1222
1223   int ep_count=0;
1224   int result;
1225
1226   _DtSvcProcessLock();
1227   while(environ[ep_count])
1228     ep_count++;
1229   
1230   result = SPC_Send_Multi_Packet(connection, prot, environ, ep_count,
1231                                ENVIRON_RESET, "  <-- ENVIRON_RESET",
1232                                SPC_Env_Too_Big);
1233   _DtSvcProcessUnlock();
1234   return (result);
1235 }
1236
1237 /*----------------------------------------------------------------------+*/
1238 int sprint_counted_string(XeString buf,
1239                           int count,
1240                           XeString *vect,
1241                           int orig_limit)
1242 /*----------------------------------------------------------------------+*/
1243 {
1244   XeString bufptr=buf;
1245   int len;
1246   int i;
1247   int limit=orig_limit;
1248 #define ERRBUFLEN 100
1249   char errbuf[ERRBUFLEN];
1250
1251   len=sprintf_len(bufptr, (XeString)"%x ", count)+1;
1252   if(len>limit) {
1253     sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1254     SPC_Error(SPC_Arg_Too_Long,
1255               bufptr,
1256               errbuf);
1257     return(SPC_ERROR);
1258   }
1259   bufptr += len;
1260   limit  -= len;
1261   
1262   for(i=0; i<count; (i++, vect++)) {
1263     if (*vect)
1264       len = strlen(*vect)+1;
1265     else
1266       len = 1;
1267
1268     if(len>limit) {
1269       sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1270       SPC_Error(SPC_Arg_Too_Long,
1271                 *vect,
1272                 errbuf);
1273       return(SPC_ERROR);
1274     }
1275     sprintf(bufptr, "%s", *vect ? *vect : "");
1276     bufptr += len;
1277     limit  -= len;
1278   }
1279   
1280   return(bufptr-buf);
1281 }
1282
1283 /*----------------------------------------------------------------------+*/
1284 XeString *sscan_counted_string(XeString buf,
1285                                XeString *newbuf)
1286 /*----------------------------------------------------------------------+*/
1287 {
1288   
1289   int i, numstrings, len;
1290   XeString bufptr; 
1291   XeString *tmpptr;
1292   XeString *tmpidx;
1293   
1294   sscanf(buf, (XeString)"%x", &numstrings);
1295   len=strlen(buf)+1;
1296   bufptr=buf+len;
1297   
1298   tmpptr=(XeString*)XeMalloc((numstrings+1) * sizeof(XeString *));
1299   tmpidx=tmpptr;
1300   
1301   for(i=0; i<numstrings; (i++, tmpidx++)){
1302     len=strlen(bufptr)+1;  /* len is string SIZE (with room for NULL) */
1303     *tmpidx=(XeString)XeMalloc(len);
1304     strncpy(*tmpidx, bufptr, len);
1305     (*tmpidx)[len-1]=NULL;
1306     bufptr+= len;
1307   }
1308   *tmpidx=NULL;
1309   if (newbuf)
1310     *newbuf=bufptr;
1311   return(tmpptr);
1312 }
1313
1314 /*----------------------------------------------------------------------+*/
1315 int 
1316 sprint_application_data(XeString buf,
1317                         XeString UNUSED_PARM(fmt),
1318                         XeString path,
1319                         XeString dir,
1320                         XeString *argv,
1321                         XeString *envp,
1322                         int      UNUSED_PARM(chars_used))
1323 /*----------------------------------------------------------------------+*/
1324 {
1325
1326   int av_count=0;
1327   int ep_count=0;
1328   int data_len=0;
1329   int tmp_len;
1330   int limit;
1331   
1332   if(argv)
1333     while(argv[av_count]) av_count++;
1334   
1335   if(envp)
1336     while(envp[ep_count]) ep_count++;
1337
1338   limit=SPC_BUFSIZ;
1339     
1340   tmp_len = sprint_counted_string(buf, 1, &path, limit);
1341   if(tmp_len == SPC_ERROR)
1342     return(SPC_ERROR);
1343   limit    -= tmp_len;
1344   buf      += tmp_len;
1345   data_len += tmp_len;
1346   
1347   tmp_len = sprint_counted_string(buf, 1, &dir, limit);
1348   if(tmp_len == SPC_ERROR)
1349     return(SPC_ERROR);
1350   limit    -= tmp_len;
1351   buf      += tmp_len;
1352   data_len += tmp_len;
1353   
1354   tmp_len = sprint_counted_string(buf, av_count, argv, limit);
1355   if(tmp_len == SPC_ERROR)
1356     return(SPC_ERROR);
1357   limit    -= tmp_len;
1358   buf      += tmp_len;
1359   data_len += tmp_len;
1360   
1361   tmp_len = sprint_counted_string(buf, ep_count, envp, limit);
1362   if(tmp_len == SPC_ERROR)
1363     return(SPC_ERROR);
1364   limit    -= tmp_len;
1365   buf      += tmp_len;
1366   data_len += tmp_len;
1367   
1368   return(data_len);
1369 }
1370
1371 /*----------------------------------------------------------------------+*/
1372 int
1373 sscan_application_data(XeString buf,
1374                        XeString UNUSED_PARM(fmt),
1375                        XeString *path,
1376                        XeString *dir,
1377                        XeString **argv,
1378                        XeString **envp,
1379                        int      UNUSED_PARM(offset))
1380 /*----------------------------------------------------------------------+*/
1381 {
1382   XeString bufptr;
1383   XeString *tmp_vect;
1384   
1385   bufptr=buf;
1386
1387   tmp_vect=sscan_counted_string(bufptr, &bufptr);
1388   if(tmp_vect==SPC_ERROR)
1389     return(SPC_ERROR);
1390   *path = (*tmp_vect);
1391   
1392   tmp_vect=sscan_counted_string(bufptr, &bufptr);
1393   if(tmp_vect==SPC_ERROR)
1394     return(SPC_ERROR);
1395   *dir = (*tmp_vect);
1396   
1397   *argv=sscan_counted_string(bufptr, &bufptr);
1398   if(*argv==SPC_ERROR)
1399     return(SPC_ERROR);
1400
1401   *envp=sscan_counted_string(bufptr, &bufptr);
1402   if(*envp==SPC_ERROR)
1403     return(SPC_ERROR);
1404 }
1405
1406 /*----------------------------------------------------------------------+*/
1407 int
1408 sprint_device_data(XeString buf,
1409                    XeString m0, 
1410                    XeString s0, 
1411                    XeString m1, 
1412                    XeString s1, 
1413                    XeString m2, 
1414                    XeString s2)
1415 /*----------------------------------------------------------------------+*/
1416 {
1417   XeString args[6];
1418   int i;
1419
1420   args[0]=m0;
1421   args[1]=s0;
1422   args[2]=m1;
1423   args[3]=s1;
1424   args[4]=m2;
1425   args[5]=s2;
1426
1427   i=sprint_counted_string(buf, 6, args, SPC_BUFSIZ);
1428   if(i==SPC_ERROR)
1429     return(SPC_ERROR);
1430   return(i);
1431 }
1432
1433 /*----------------------------------------------------------------------+*/
1434 int
1435 sscan_device_data(XeString buf,
1436                   XeString *m0, 
1437                   XeString *s0, 
1438                   XeString *m1, 
1439                   XeString *s1, 
1440                   XeString *m2, 
1441                   XeString *s2)
1442 /*----------------------------------------------------------------------+*/
1443 {
1444   XeString *args;
1445
1446   args=sscan_counted_string(buf, NULL);
1447
1448   if(args==SPC_ERROR)
1449     return(SPC_ERROR);
1450   
1451   *m0=args[0];
1452   *s0=args[1];
1453   *m1=args[2];
1454   *s1=args[3];
1455   *m2=args[4];
1456   *s2=args[5];
1457
1458   free((char *)args);
1459   
1460   return(TRUE);
1461 }
1462
1463 /*----------------------------------------------------------------------+*/
1464 int
1465 sprint_logfile_data(XeString buf,
1466                     XeString logfile,
1467                     XeString proto_ver,
1468                     XeString hostinfo)
1469 /*----------------------------------------------------------------------+*/
1470 {
1471   int i;
1472   XeString args[3];
1473   
1474   args[0]=logfile;
1475   args[1]=proto_ver;
1476   args[2]=hostinfo;
1477   
1478   i=sprint_counted_string(buf, 3, args, SPC_BUFSIZ);
1479   if(i==SPC_ERROR)
1480     return(SPC_ERROR);
1481   return(i);
1482 }
1483
1484 /*----------------------------------------------------------------------+*/
1485 int
1486 sscan_logfile_data(XeString buf,
1487                    XeString *logfile,
1488                    XeString *proto_ver,
1489                    XeString *hostinfo)
1490 /*----------------------------------------------------------------------+*/
1491 {
1492   XeString *args;
1493
1494   args=sscan_counted_string(buf, NULL);
1495
1496   if(args==SPC_ERROR)
1497     return(SPC_ERROR);
1498   
1499   *logfile=args[0];
1500   /* args[1] and args[2] will only be around for protocol revision 2 or later */
1501
1502   *proto_ver = *hostinfo = XeString_NULL;
1503
1504   if (args[1]) { 
1505       *proto_ver = args[1];
1506       *hostinfo  = args[2];
1507   }
1508   else
1509       *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);     
1510
1511   free((char *)args);
1512   
1513   return(TRUE);
1514 }
1515
1516 /*----------------------------------------------------------------------+*/
1517 int
1518 sprint_register_data(XeString buf,
1519                      XeString username, 
1520                      XeString passwd,
1521                      XeString proto_ver,
1522                      XeString hostinfo)
1523 /*----------------------------------------------------------------------+*/
1524 {
1525   int i;
1526   XeString args[4];
1527
1528   args[0]=username;
1529   args[1]=passwd;
1530   args[2]=proto_ver;
1531   args[3]=hostinfo;  
1532   
1533   i=sprint_counted_string(buf, 4, args, SPC_BUFSIZ);
1534   if(i==SPC_ERROR)
1535     return(SPC_ERROR);
1536   return(i);
1537 }
1538
1539 /*----------------------------------------------------------------------+*/
1540 int
1541 sscan_register_data(XeString buf,
1542                     XeString *username,
1543                     XeString *passwd,
1544                     XeString *proto_ver,
1545                     XeString *hostinfo)
1546 /*----------------------------------------------------------------------+*/
1547 {
1548   XeString *args;
1549
1550   args=sscan_counted_string(buf, NULL);
1551
1552   if(args==SPC_ERROR)
1553     return(SPC_ERROR);
1554   
1555   *username=args[0];
1556   *passwd=args[1];
1557
1558   /* args[2] and args[3] will only be around for protocol revision 2 or later */
1559
1560   *proto_ver = *hostinfo = XeString_NULL;
1561
1562   if (args[2]) { 
1563       *proto_ver = args[2];
1564       *hostinfo  = args[3];
1565   }
1566   else
1567       *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);     
1568
1569   free((char *)args);
1570   
1571   return(TRUE);
1572 }
1573
1574 /*
1575  **
1576  ** Request / reply protocol requests
1577  **
1578 */
1579
1580 /*----------------------------------------------------------------------+*/
1581 int SPC_Query_Devices(SPC_Channel_Ptr channel)
1582 /*----------------------------------------------------------------------+*/
1583 {
1584   SPC_Connection_Ptr connection=channel->connection;
1585   protocol_request_ptr prot;
1586   
1587   SPC_Write_Protocol_Request(connection, channel, QUERY_DEVICES);
1588   prot=SPC_Filter_Connection(connection, channel, DEVICE_REPLY, TRUE);
1589   if(prot==SPC_ERROR)
1590     return(SPC_ERROR);
1591   
1592   READ_DEVICE_REPLY(prot->dataptr,
1593                     &(channel->wires[STDIN]->master_name),
1594                     &(channel->wires[STDIN]->slave_name),
1595                     &(channel->wires[STDOUT]->master_name),
1596                     &(channel->wires[STDOUT]->slave_name),
1597                     &(channel->wires[STDERR]->master_name),
1598                     &(channel->wires[STDERR]->slave_name));
1599
1600   SPC_Free_Protocol_Ptr(prot);
1601   return (TRUE);
1602 }
1603
1604 /*----------------------------------------------------------------------+*/
1605 int SPC_Query_Logfile(SPC_Channel_Ptr channel)
1606 /*----------------------------------------------------------------------+*/
1607 {
1608   SPC_Connection_Ptr connection=channel->connection;
1609   protocol_request_ptr prot;
1610   XeString junk1, junk2;
1611   
1612   SPC_Write_Protocol_Request(connection, channel, QUERY_LOGFILE);
1613   prot=SPC_Filter_Connection(connection, channel, LOGFILE_REPLY, TRUE);
1614   if(prot==SPC_ERROR)
1615     return(SPC_ERROR);
1616   
1617   READ_LOGFILE_REPLY(prot->dataptr, &channel->logfile, &junk1, &junk2);
1618   if (junk1) XeFree(junk1);
1619   if (junk1) XeFree(junk2);
1620                      
1621   SPC_Free_Protocol_Ptr(prot);
1622   return (TRUE);
1623 }
1624
1625 #define UNK_TOKEN       "unknown"
1626
1627 /*----------------------------------------------------------------------+*/
1628 XeString SPC_LocalHostinfo(void)
1629 /*----------------------------------------------------------------------+*/
1630 {
1631     struct utsname      name;
1632     int                 s_len;
1633     static XeString     s = 0;
1634
1635     _DtSvcProcessLock();
1636     if (!s) {
1637         if (uname(&name) >= 0) {
1638             s_len = strlen(name.sysname) +
1639                     strlen(name.nodename) +
1640                     strlen(name.release) +
1641                     strlen(name.machine) + 4;
1642             s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1643             sprintf(s, "%s:%s:%s:%s", name.nodename, name.sysname, name.release, name.machine);
1644         }
1645         else {
1646             s_len = 4 * strlen(UNK_TOKEN) + 4;
1647             s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1648             sprintf(s, "%s:%s:%s:%s", UNK_TOKEN, UNK_TOKEN, UNK_TOKEN, UNK_TOKEN);
1649         }
1650     }
1651
1652     _DtSvcProcessUnlock();
1653     return s;
1654 }
1655
1656 /*----------------------------------------------------------------------+*/
1657 int
1658 SPC_Validate_User(XeString hostname,
1659                   SPC_Connection_Ptr connection)
1660 /*----------------------------------------------------------------------+*/
1661     /* Called by client to register itself to spcd */
1662 {
1663   XeString username = XeString_NULL;
1664   uid_t this_uid;
1665   XeString proto_ver;
1666   XeString hostinfo;
1667   XeString path;
1668   protocol_request_ptr prot;
1669   int open_status, chmod_status;
1670   XeString logfile = NULL;
1671   XeString junk1 = NULL, junk2 = NULL;
1672   XeString connection_hostname=CONNECTION_HOSTNAME(connection);
1673   _Xgetpwparams pwd_buf;
1674   struct passwd * pwd_ret;
1675
1676   hostinfo = SPC_LocalHostinfo();
1677
1678   /*
1679    *  We are now including the user ID to generate the LOGFILE
1680    *  (i.e., the authentication file)
1681    */
1682   this_uid=getuid();
1683
1684   if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) == NULL) {
1685     /* 
1686      * Very strange situation - the uid isn't in the passwd file 
1687      */
1688     username = XeString_NULL;  /* we'll use the original /tmp subdirectory */
1689   }
1690   else {
1691     username=(XeString)(pwd_ret->pw_name);
1692   }
1693
1694   SPC_Write_Protocol_Request(connection, NULL, REGISTER, 
1695                              username, XeString_Empty, 
1696                              SPC_PROTOCOL_VERSION_STR, hostinfo);
1697
1698   
1699   prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1700   if(prot==SPC_ERROR) {
1701     XeFree(connection_hostname);
1702     return(SPC_ERROR);
1703   }
1704
1705   /* In repsonse to the register, the daemon will send back a LOGFILE_REPLY */
1706   /* message that contains the name of a logfile to be used to do user      */
1707   /* authentication.  For A.02 and later daemons, it will also contain      */
1708   /* the spc protocol version and info about the host the daemon is on.     */
1709
1710   READ_LOGFILE_REPLY(prot->dataptr, &logfile, &proto_ver, &hostinfo);
1711
1712   /* For Pre A.01, this will be defaulted to (hpux 7.0 s300) */
1713   connection->hostinfo = hostinfo;
1714
1715   if (proto_ver) {
1716      sscanf(proto_ver, "%d", &connection->protocol_version);
1717      XeFree(proto_ver);
1718    }
1719
1720   SPC_Free_Protocol_Ptr(prot);
1721
1722   if(!strcmp(logfile, PASSED_FILE_NAME))
1723     return(TRUE);
1724   if(!strcmp(logfile, FAILED_FILE_NAME)) {
1725     SPC_Error(SPC_Register_Username,
1726               (username) ? username : (XeString)"<empty user>",
1727               connection_hostname);
1728     XeFree(connection_hostname);
1729     if (logfile) XeFree(logfile);
1730     return(SPC_ERROR);
1731   }
1732
1733   /*
1734    * Get a pathname to the authentication file.
1735    */
1736   path=tt_netfile_file(logfile);
1737   
1738   if(tt_ptr_error (path) != TT_OK) {
1739     SPC_Write_Protocol_Request(connection, NULL, ABORT);
1740     SPC_Error(SPC_Register_Netrc,
1741               logfile,
1742               connection_hostname);
1743     XeFree(connection_hostname);
1744     if (logfile) XeFree(logfile);
1745     return(SPC_ERROR);
1746   }
1747
1748   open_status=open(path, O_CREAT, S_ISUID);
1749   if(open_status==ERROR) {
1750     SPC_Write_Protocol_Request(connection, NULL, ABORT);
1751     SPC_Error(SPC_Register_Open,
1752               path,
1753               connection_hostname);
1754     tt_free (path);
1755     XeFree(connection_hostname);
1756     if (logfile) XeFree(logfile);
1757     return(SPC_ERROR);
1758   }
1759   
1760   /* We need to also do a chmod because of an apparent Domain/OS bug
1761      where the open call does not properly set the UID bit.  We
1762      let chmod set the bit. */
1763
1764   chmod_status=chmod(path, S_ISUID);
1765   if(chmod_status==ERROR) {
1766     SPC_Write_Protocol_Request(connection, NULL, ABORT);
1767     SPC_Error(SPC_Register_Open,
1768               path,
1769               connection_hostname);
1770     tt_free (path);
1771     XeFree(connection_hostname);
1772     if (logfile) XeFree(logfile);
1773     return(SPC_ERROR);
1774   }
1775   
1776   SPC_Write_Protocol_Request(connection, NULL, REGISTER, logfile, NULL, NULL, NULL);
1777   prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1778
1779   close(open_status);
1780   unlink(path);
1781   tt_free (path);
1782   
1783   if(prot==SPC_ERROR) {
1784     XeFree(connection_hostname);
1785     return(SPC_ERROR);
1786   }
1787   
1788   /*
1789    * Free logfile before it gets malloc'd again.
1790    */
1791   XeFree(logfile);
1792   logfile = NULL;
1793   READ_LOGFILE_REPLY(prot->dataptr, &logfile, &junk1, &junk2);
1794   if (junk1) XeFree(junk1);
1795   if (junk2) XeFree(junk2);
1796   
1797   SPC_Free_Protocol_Ptr(prot);
1798
1799   if(!strcmp(logfile, PASSED_FILE_NAME)) {
1800     XeFree(connection_hostname);
1801     if (logfile) XeFree(logfile);
1802     return(TRUE);
1803   }
1804   if(!strcmp(logfile, FAILED_FILE_NAME)) {
1805     SPC_Error(SPC_Register_Handshake,
1806               username,
1807               connection_hostname);
1808     XeFree(connection_hostname);
1809     if (logfile) XeFree(logfile);
1810     return(SPC_ERROR);
1811   }
1812
1813   if (logfile) XeFree(logfile);
1814   XeFree(connection_hostname);
1815   SPC_Error(SPC_Protocol);
1816   return(SPC_ERROR);
1817 }
1818
1819
1820 /*----------------------------------------------------------------------+*/
1821 static int SPC_Send_Termios(protocol_request_ptr prot_request)
1822 /*----------------------------------------------------------------------+*/
1823 {
1824   struct termios *tio;
1825   int retval;
1826   XeString s;
1827
1828   tio = SPC_Get_Current_Termio();       /* Gets a (malloced) copy */
1829   s = SPC_Decode_Termios( tio );        /* Get ASCII representation */
1830   
1831   retval = WRITE_STRING(prot_request->dataptr, s);
1832   XeFree(tio);
1833   XeFree(s);
1834
1835   return(retval);
1836   
1837 }
1838
1839
1840 /*----------------------------------------------------------------------+*/
1841 int SPC_Get_Termios(protocol_request_ptr prot_request)
1842 /*----------------------------------------------------------------------+*/
1843 {
1844     XeString s;
1845     int      i;
1846
1847     _DtSvcProcessLock();
1848     if(XeTermioStruct == NULL) {
1849         XeTermioStruct = (struct termios *)XeMalloc(sizeof(struct termios));
1850
1851         for(i=0; i<NCCS; i++) 
1852             XeTermioStruct->c_cc[i] = 0;
1853     }
1854     
1855     READ_STRING_NO_COPY(prot_request->dataptr, s);
1856     
1857     SPC_Encode_Termios(s, XeTermioStruct);
1858
1859     _DtSvcProcessUnlock();
1860     return(XeSetpgrp(FALSE));
1861 }
1862
1863
1864
1865 /*----------------------------------------------------------------------+*/
1866 int SPC_Get_Termio(protocol_request_ptr UNUSED_PARM(prot_request))
1867 /*----------------------------------------------------------------------+*/
1868 {
1869     /* This is for old 1.0, 1.1 versions of the SPC code.  We used to  */
1870     /* pass an HPUX version of the termio struct around.  This was not */
1871     /* portable. If we get one of these requests, just bit bucket it   */
1872     /* as we do not know how to deal with it.                          */
1873
1874     return(XeSetpgrp(FALSE));
1875 }
1876
1877 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
1878                               protocol_request_ptr prot,
1879                               char *path,
1880                               char *dir,
1881                               char **argv,
1882                               char **envp)
1883 {
1884   char **merged_ptr;
1885   int num_elts=0, this_elt, num_argv, num_envp;
1886   char argv_buf[20], envp_buf[20];
1887   int retval;
1888   
1889   num_argv = 0;
1890   while(argv && argv[num_argv++])
1891     num_elts++;
1892
1893   num_envp = 0;
1894   while(envp && envp[num_envp++])
1895     num_elts++;
1896
1897   merged_ptr = (char **)malloc((num_elts+6) * sizeof(char *));
1898
1899   sprintf(argv_buf, "%d", num_argv);
1900   sprintf(envp_buf, "%d", num_envp);
1901   
1902   num_elts=0;
1903   merged_ptr[num_elts++] = path;
1904   merged_ptr[num_elts++] = dir;
1905   merged_ptr[num_elts++] = argv_buf;
1906   merged_ptr[num_elts++] = envp_buf;
1907
1908   this_elt = 0;
1909   while(argv && argv[this_elt])
1910     merged_ptr[num_elts++] = argv[this_elt++];
1911   
1912   merged_ptr[num_elts++] = "DUMMY";
1913
1914   this_elt = 0;
1915   while(envp && envp[this_elt])
1916     merged_ptr[num_elts++] = envp[this_elt++];
1917
1918   merged_ptr[num_elts] = NULL;
1919   
1920   retval = SPC_Send_Multi_Packet(connection, prot,
1921                                  merged_ptr, num_elts,
1922                                  APP_B00_SPAWN, "  <-- APP_B00_SPAWN",
1923                                  SPC_Arg_Too_Long);
1924   
1925   free((char *)merged_ptr);
1926
1927   return(retval);
1928 }