1 /*
2  * wmslib/src/but/net.c, part of wmslib (Library functions)
3  * Copyright (C) 1995-1997 William Shubert.
4  * See "configure.h.in" for more copyright information.
5  */
6 
7 #include <configure.h>
8 
9 #if  X11_DISP
10 
11 #ifdef  STDC_HEADERS
12 #include <stdlib.h>
13 #include <unistd.h>
14 #endif  /* STDC_HEADERS */
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <X11/cursorfont.h>
20 #include <X11/Xatom.h>
21 #include <X11/keysym.h>
22 #include <sys/time.h>
23 #ifdef  HAVE_SYS_SELECT_H
24 #include <sys/select.h>
25 #endif
26 #include <sys/types.h>
27 
28 #if  HAVE_SOCKETS
29 
30 #include <sys/socket.h>
31 #if  HAVE_NETINET_IN_H
32 #include <netinet/in.h>
33 #endif
34 #if  HAVE_SYS_IN_H
35 #include <sys/in.h>
36 #endif
37 #if  HAVE_SYS_INET_H
38 #include <sys/inet.h>
39 #endif
40 #include <netdb.h>
41 #if  HAVE_ARPA_NAMESER_H
42 
43 #include <arpa/nameser.h>
44 #endif
45 #if  HAVE_RESOLV_H
46 #include <resolv.h>
47 #endif
48 #if  HAVE_SYS_UTSNAME_H
49 #include <sys/utsname.h>
50 #endif
51 #include <pwd.h>
52 
53 #endif  /* HAVE_SOCKETS */
54 
55 #include <fcntl.h>
56 #include <wms.h>
57 #include <but/but.h>
58 #include <but/net.h>
59 
60 #if  HAVE_SOCKETS
61 
62 /**********************************************************************
63  * Forward Declarations
64  **********************************************************************/
65 
66 static ButOut  newConn(void *packet, int fd);
67 static ButRnet  *newRnet(ButEnv *env);
68 static ButOut  getNetData(void *packet, int fd);
69 static ButOut  finishWrite(void *packet, int fd);
70 static void  putProtoWho(ButRnet *net);
71 static void  butRnet_close(ButRnet *net, const char *reason, bool forced);
72 static bool  butRnet_write(ButRnet *net, ButNetMsg *msg);
73 static void  butRnet_sendMMove(ButRnet *net, int winId, int lx, int ly,
74 			       int lw, int lh, ButCur type);
75 static void  newFlags(ButRnet *net, int id, uint newFlags);
76 static ButOut  butSpec(ButEnv *env, int butId, void *buf, int bufLen);
77 
78 
79 /**********************************************************************
80  * Functions
81  **********************************************************************/
82 
butLnet_create(ButEnv * env,int port,void * packet,ButOut ocallback (ButRnet * net),ButOut callback (ButRnet * net,void * cmd,int cmdLen),ButOut ccallback (ButRnet * net,const char * reason))83 ButLnet  *butLnet_create(ButEnv *env, int port, void *packet,
84 			 ButOut ocallback(ButRnet *net),
85 			 ButOut callback(ButRnet *net, void *cmd, int cmdLen),
86 			 ButOut ccallback(ButRnet *net, const char *reason))  {
87   ButLnet  *net = wms_malloc(sizeof(ButLnet));
88   struct sockaddr_in  sa;
89 
90   MAGIC_SET(net);
91   net->env = env;
92   net->packet = packet;
93   net->valid = net->error = FALSE;
94   net->fd = socket(AF_INET, SOCK_STREAM, 0);
95   net->ocallback = ocallback;
96   net->callback = callback;
97   net->ccallback = ccallback;
98   if (net->fd == -1)  {
99     net->error = TRUE;
100     net->errNum = errno;
101     return(net);
102   }
103   sa.sin_family = AF_INET;
104   sa.sin_addr.s_addr = INADDR_ANY;
105   sa.sin_port = htons(port);
106   if (bind(net->fd, (struct sockaddr *)&sa, sizeof(sa)) != 0)  {
107     net->error = TRUE;
108     net->errNum = errno;
109     close(net->fd);
110     return(net);
111   }
112   if (listen(net->fd, 2) != 0)  {
113     net->error = TRUE;
114     net->errNum = errno;
115     close(net->fd);
116     return(net);
117   }
118   butEnv_addFile(env, BUT_READFILE, net->fd, net, newConn);
119   net->valid = TRUE;
120   return(net);
121 }
122 
123 
butRnet_create(ButEnv * env,const char * address,int port,void * packet,ButOut ocallback (ButRnet * net),ButOut callback (ButRnet * net,void * cmd,int cmdLen),ButOut ccallback (ButRnet * net,const char * reason))124 ButRnet  *butRnet_create(ButEnv *env, const char *address, int port,
125 			 void *packet, ButOut ocallback(ButRnet *net),
126 			 ButOut callback(ButRnet *net, void *cmd, int cmdLen),
127 			 ButOut ccallback(ButRnet *net, const char *reason))  {
128   ButRnet  *net;
129   struct sockaddr_in  sa;
130   struct hostent  *hp;
131 
132   net = newRnet(env);
133   net->packet = packet;
134   net->state = butRnetState_closed;
135   net->error = net->lookupError = net->butNetError = FALSE;
136   net->ocallback = ocallback;
137   net->callback = callback;
138   net->ccallback = ccallback;
139   if ((net->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  {
140     net->error = TRUE;
141     net->errNum = errno;
142     return(net);
143   }
144   sa.sin_family = AF_INET;
145   if ((hp = gethostbyname(address)) == NULL)  {
146     net->lookupError = TRUE;
147 #if  HAVE_H_ERRNO
148     net->errNum = h_errno;
149 #else
150     net->errNum = HOST_NOT_FOUND;
151 #endif
152     return(net);
153   }
154   memcpy(&sa.sin_addr, hp->h_addr, hp->h_length);
155   sa.sin_port = htons(port);
156   if (connect(net->fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)  {
157     net->error = TRUE;
158     net->errNum = errno;
159     return(net);
160   }
161   net->state = butRnetState_pwWait;
162   fcntl(net->fd, F_SETFL, O_NONBLOCK);
163   putProtoWho(net);
164   butEnv_addFile(net->env, BUT_READFILE, net->fd, net, getNetData);
165   return(net);
166 }
167 
168 
butRnet_accept(ButRnet * net)169 void  butRnet_accept(ButRnet *net)  {
170   assert(net->state == butRnetState_accWait);
171   net->state = butRnetState_open;
172   net->lType = net->env->curlast;
173   net->env->curlast = butCur_bogus;  /* Force the cursor type to be sent. */
174   putProtoWho(net);
175 }
176 
177 
butLnet_destroy(ButLnet * net)178 void  butLnet_destroy(ButLnet *net)  {
179   assert(MAGIC(net));
180   if (net->valid)  {
181     close(net->fd);
182     butEnv_rmFile(net->env, BUT_READFILE, net->fd);
183   }
184   MAGIC_UNSET(net);
185   wms_free(net);
186 }
187 
188 
butRnet_destroy(ButRnet * net,const char * reason)189 void  butRnet_destroy(ButRnet *net, const char *reason)  {
190   ButNetMsg  msgOut;
191 
192   assert(MAGIC(net));
193   if (net->state < butRnetState_closing)  {
194     msgOut.type = int_stdInt32(BUTNET_CLOSE);
195     msgOut.length = int_stdInt32(2*4+strlen(reason)+1);
196     strcpy(msgOut.perType.close, reason);
197     butRnet_write(net, &msgOut);
198     butRnet_close(net, NULL, FALSE);
199   }
200 }
201 
202 
newConn(void * packet,int fd)203 static ButOut  newConn(void *packet, int fd)  {
204   ButLnet  *lnet = packet;
205   ButRnet  *rnet;
206   struct sockaddr_in  addr;
207   int  addrlen = sizeof(addr);
208 
209   assert(MAGIC(lnet));
210   rnet = newRnet(lnet->env);
211   rnet->fd = accept(lnet->fd, (struct sockaddr *)&addr, &addrlen);
212   if (rnet->fd < 0)  {
213     rnet->env->partners[rnet->partner] = NULL;
214     MAGIC_UNSET(rnet);
215     wms_free(rnet);
216     return(0);
217   }
218   rnet->packet = lnet->packet;
219   rnet->ocallback = lnet->ocallback;
220   rnet->callback = lnet->callback;
221   rnet->ccallback = lnet->ccallback;
222   fcntl(rnet->fd, F_SETFL, O_NONBLOCK);
223   rnet->state = butRnetState_pwAccWait;
224   butEnv_addFile(rnet->env, BUT_READFILE, rnet->fd, rnet, getNetData);
225   return(0);
226 }
227 
228 
newRnet(ButEnv * env)229 static ButRnet  *newRnet(ButEnv *env)  {
230   ButRnet  *net = wms_malloc(sizeof(ButRnet));
231   int  newNumPartners, i, partner;
232   ButRnet  **newPartners;
233 
234   MAGIC_SET(net);
235   for (partner = 0;  partner < env->numPartners;  ++partner)  {
236     if (!env->partners[partner])
237       break;
238   }
239   if (partner == env->numPartners)  {
240     newNumPartners = (env->numPartners + 1) * 2;
241     newPartners = wms_malloc(newNumPartners * sizeof(ButRnet *));
242     for (i = 0;  i < env->numPartners;  ++i)  {
243       newPartners[i] = env->partners[i];
244     }
245     for (;  i < newNumPartners;  ++i)
246       newPartners[i] = NULL;
247     if (env->partners)
248       wms_free(env->partners);
249     env->numPartners = newNumPartners;
250     env->partners = newPartners;
251   }
252   env->partners[partner] = net;
253   net->partner = partner;
254   net->env = env;
255   net->error = FALSE;
256   net->wBufSize = net->wBufStart = net->wBufLen = 0;
257   net->wBuffer = NULL;
258   net->rBufAmt = 0;
259   net->rBufLen = BUTNET_MAXCMD * 2 + 2;
260   net->fd = -1;
261   net->ackNeeded = net->mouseMove = FALSE;
262   net->who = "Unknown";
263   net->protocol = "Unknown";
264   if ((env->last_mwin) && (env->last_mx >= 0))  {
265     assert(MAGIC(env->last_mwin));
266     net->lWinId = env->last_mwin->id;
267     net->lx = env->last_mx;
268     net->ly = env->last_my;
269     net->lw = env->last_mwin->w;
270     net->lh = env->last_mwin->h;
271     net->lType = env->curnum;
272   } else
273     net->lWinId = -2;
274   net->lPress = net->lTwitch = -1;
275   butRcur_create(&net->rc, net->env);
276   return(net);
277 }
278 
279 
280 /* Returns TRUE if success. */
butRnet_write(ButRnet * net,ButNetMsg * msg)281 static bool  butRnet_write(ButRnet *net, ButNetMsg *msg)  {
282   int  len = stdInt32_int(msg->length) + 8;
283   int  amtWritten;
284   char  *remainder = (char *)msg;
285 
286   assert(MAGIC(net));
287   if (net->wBufLen == 0)  {
288     /* Nothing queued up.  Try to write directly! */
289     amtWritten = write(net->fd, msg, len);
290     if (amtWritten == len)
291       return(TRUE);
292     if (amtWritten < 0)  {
293       butRnet_close(net, strerror(errno), TRUE);
294       return(FALSE);
295     }
296     remainder += amtWritten;
297     len -= amtWritten;
298   }
299   /* Not all got written.  Put some into the wBuffer. */
300   if (len + net->wBufStart + net->wBufLen > net->wBufSize)  {
301     char  *newBuf;
302 
303     newBuf = wms_malloc(net->wBufSize = len + net->wBufStart + net->wBufLen);
304     if (net->wBufLen)
305       memcpy(newBuf, net->wBuffer+net->wBufStart, net->wBufLen);
306     net->wBufStart = 0;
307     if (net->wBuffer)
308       wms_free(net->wBuffer);
309     net->wBuffer = newBuf;
310   }
311   memcpy(remainder, net->wBuffer + net->wBufStart + net->wBufLen, len);
312   net->wBufLen += len;
313   butEnv_addFile(net->env, BUT_WRITEFILE, net->fd, net, finishWrite);
314   return(TRUE);
315 }
316 
317 
finishWrite(void * packet,int fd)318 static ButOut  finishWrite(void *packet, int fd)  {
319   ButRnet  *net = packet;
320   int  amtWritten;
321 
322   assert(MAGIC(net));
323   amtWritten = write(net->fd, net->wBuffer + net->wBufStart, net->wBufLen);
324   if (amtWritten == net->wBufLen)  {
325     butEnv_rmFile(net->env, BUT_WRITEFILE, net->fd);
326     net->wBufLen = 0;
327     net->wBufStart = 0;
328     if (net->state == butRnetState_closing)  {
329       close(net->fd);
330       net->fd = -1;
331       MAGIC_UNSET(net);
332       wms_free(net);
333     }
334   } else if (amtWritten < 0)  {
335     butRnet_close(net, strerror(errno), TRUE);
336     return(0);
337   } else  {
338     net->wBufStart += amtWritten;
339     net->wBufLen -= amtWritten;
340   }
341   return(0);
342 }
343 
344 
getNetData(void * packet,int fd)345 static ButOut  getNetData(void *packet, int fd)  {
346   ButRnet  *net = packet;
347   int  readLen, i, msgType;
348   ButOut  res = 0;
349   char  *temp;
350 
351   assert(MAGIC(net));
352   if (net->rBufAmt < 4)  {
353     /* Waiting for the length count. */
354     readLen = read(fd, (char *)&net->rBuffer + net->rBufAmt, 4 - net->rBufAmt);
355     if (readLen <= 0)  {
356       if (readLen == 0)
357 	butRnet_close(net, "Connection closed", TRUE);
358       else if ((readLen < 0) && (errno != EAGAIN))
359 	butRnet_close(net, strerror(errno), TRUE);
360       return(res);
361     }
362     if ((net->rBufAmt += readLen) < 4)
363       return(0);
364     net->rBufMsgLen = stdInt32_int(net->rBuffer.length);
365     if (net->rBufMsgLen > BUTNET_MAXCMD)  {
366       fprintf(stderr, "Bogus command\n");
367       for (;;);
368     }
369     net->rBufMsgLen += 8;
370     return(0);
371   }
372   if ((net->rBufMsgLen > BUTNET_MAXCMD+8) ||
373       (net->rBufMsgLen < 8))  {
374     butRnet_close(net, "Invalid data on connection", TRUE);
375     return(res);
376   }
377   readLen = read(fd, (char *)&net->rBuffer + net->rBufAmt,
378 		 net->rBufMsgLen - net->rBufAmt);
379   if (readLen <= 0)  {
380     if (readLen == 0)
381       butRnet_close(net, "Connection closed", TRUE);
382     else if ((readLen < 0) && (errno != EAGAIN))
383       butRnet_close(net, strerror(errno), TRUE);
384     return(res);
385   }
386   net->rBufAmt += readLen;
387   if (net->rBufAmt == net->rBufMsgLen)  {
388     msgType = stdInt32_int(net->rBuffer.type);
389     net->rBufAmt = 0;
390     switch(msgType)  {
391     case BUTNET_PROTOWHO:
392       if (net->state == butRnetState_pwWait)  {
393 	net->state = butRnetState_open;
394 	/* Force the cursor type to be sent. */
395 	net->lType = net->env->curlast;
396 	net->env->curlast = butCur_bogus;
397       } else if (net->state == butRnetState_pwAccWait)  {
398 	net->state = butRnetState_accWait;
399       } else  {
400 	butRnet_close(net, "Invalid data on connection", TRUE);
401 	break;
402       }
403       if (net->rBufMsgLen != sizeof(net->rBuffer.perType.protoWho) + 8)  {
404 	butRnet_close(net, "Invalid data on connection", TRUE);
405 	break;
406       }
407       net->rmtPartner = stdInt32_int(net->rBuffer.perType.protoWho.context);
408       temp = wms_malloc(i = (strlen(net->rBuffer.perType.protoWho.proto) + 1));
409       strcpy(temp, net->rBuffer.perType.protoWho.proto);
410       net->protocol = temp;
411       temp = wms_malloc(strlen(net->rBuffer.perType.protoWho.who) + 1);
412       strcpy(temp, net->rBuffer.perType.protoWho.who);
413       net->who = temp;
414       return(net->ocallback(net));
415       break;
416     case BUTNET_CLOSE:
417       butRnet_close(net, net->rBuffer.perType.close, FALSE);
418       break;
419     case BUTNET_USERDATA:
420       if (net->callback)
421 	return(net->callback(net, net->rBuffer.perType.userData,
422 			     stdInt32_int(net->rBuffer.length)));
423       break;
424     case BUTNET_MOUSE:
425       if (net->rBufMsgLen != sizeof(net->rBuffer.perType.mouse) + 8)  {
426 	butRnet_close(net, "Invalid data on connection", TRUE);
427 	break;
428       }
429       butRcur_move(&net->rc, stdInt32_int(net->rBuffer.perType.mouse.win),
430 		   stdInt32_int(net->rBuffer.perType.mouse.x),
431 		   stdInt32_int(net->rBuffer.perType.mouse.y),
432 		   stdInt32_int(net->rBuffer.perType.mouse.w),
433 		   stdInt32_int(net->rBuffer.perType.mouse.h),
434 		   stdInt32_int(net->rBuffer.perType.mouse.type));
435       net->rBuffer.length = int_stdInt32(0);
436       net->rBuffer.type = int_stdInt32(BUTNET_MOUSEACK);
437       butRnet_write(net, &net->rBuffer);
438       break;
439     case BUTNET_MOUSEACK:
440       if (net->rBufMsgLen != 8)  {
441 	butRnet_close(net, "Invalid data on connection", TRUE);
442 	break;
443       }
444       net->ackNeeded = FALSE;
445       if (net->mouseMove)  {
446 	net->mouseMove = FALSE;
447 	butRnet_sendMMove(net, -1, -1,-1, -1,-1, -1);
448       }
449       break;
450     case BUTNET_NEWFLAGS:
451       if (net->rBufMsgLen != sizeof(net->rBuffer.perType.newFlags) + 8)  {
452 	butRnet_close(net, "Invalid data on connection", TRUE);
453 	break;
454       }
455       newFlags(net, stdInt32_int(net->rBuffer.perType.newFlags.butId),
456 	       stdInt32_int(net->rBuffer.perType.newFlags.newFlags));
457       break;
458     case BUTNET_BUTSPEC:
459       res |= butSpec(net->env,
460 		     stdInt32_int(net->rBuffer.perType.butSpec.butId),
461 		     net->rBuffer.perType.butSpec.butData,
462 		     stdInt32_int(net->rBuffer.length) - sizeof(StdInt32));
463       break;
464     default:
465       butRnet_close(net, "Invalid data on connection", TRUE);
466       break;
467     }
468   }
469   return(res);
470 }
471 
472 
newFlags(ButRnet * net,int id,uint newFlags)473 static void  newFlags(ButRnet *net, int id, uint newFlags)  {
474   ButEnv  *env = net->env;
475   But  *but;
476 
477   if (id < env->maxButIds)  {
478     but = env->id2But[id];
479     if (but)  {
480       if (newFlags & BUT_PRESSED)
481 	net->lPress = id;
482       else if (net->lPress == id)
483 	net->lPress = -1;
484       if (newFlags & BUT_TWITCHED)
485 	net->lTwitch = id;
486       else if (net->lTwitch == id)
487 	net->lTwitch = -1;
488       but_newFlags(but, (newFlags & (BUT_NETMASK<<BUT_NETSHIFT)) |
489 		   (but->flags & ~(BUT_NETMASK<<BUT_NETSHIFT)));
490     }
491   }
492 }
493 
494 
putProtoWho(ButRnet * net)495 static void  putProtoWho(ButRnet *net)  {
496 #if  HAVE_SYS_UTSNAME_H
497   struct utsname  unameOut;
498 #endif
499   struct passwd  *pw;
500   char  *loginName;
501   ButEnv  *env = net->env;
502   ButNetMsg  protoOut;
503 
504   assert(MAGIC(net));
505   protoOut.length = int_stdInt32(sizeof(protoOut.perType.protoWho));
506   protoOut.type = int_stdInt32(BUTNET_PROTOWHO);
507 #if  HAVE_SYS_UTSNAME_H
508   uname(&unameOut);
509 #endif
510   if ((loginName = getlogin()) == NULL)  {
511     pw = getpwuid(getuid());
512     loginName = pw->pw_name;
513   }
514   strcpy(protoOut.perType.protoWho.proto, env->protocol);
515   protoOut.perType.protoWho.proto[sizeof(protoOut.perType.protoWho.proto) -
516 				  1] = '\0';
517   sprintf(protoOut.perType.protoWho.who, "%s@%s",
518 	  loginName,
519 #if  HAVE_SYS_UTSNAME_H
520 	  unameOut.nodename
521 #else
522 	  "unknown"
523 #endif
524 	  );
525   butRnet_write(net, &protoOut);
526 }
527 
528 
butRnet_close(ButRnet * net,const char * reason,bool force)529 static void  butRnet_close(ButRnet *net, const char *reason, bool force)  {
530   ButEnv  *env = net->env;
531 
532   assert(MAGIC(net));
533   if (net->lPress != -1)  {
534     if (env->id2But[net->lPress])  {
535       but_newFlags(env->id2But[net->lPress], env->id2But[net->lPress]->flags &
536 		   ~BUT_NETPRESS);
537     }
538   }
539   if (net->lTwitch != -1)  {
540     if (env->id2But[net->lTwitch])  {
541       but_newFlags(env->id2But[net->lTwitch],
542 		   env->id2But[net->lTwitch]->flags & ~BUT_NETTWITCH);
543     }
544   }
545   if (net->state < butRnetState_closing)  {
546     if (reason && net->ccallback)
547       net->ccallback(net, reason);
548     net->state = butRnetState_closing;
549     butEnv_rmFile(net->env, BUT_READFILE, net->fd);
550     if (force || (net->wBufLen == 0))  {
551       close(net->fd);
552       net->fd = -1;
553       if (net->wBufLen != 0)
554 	butEnv_rmFile(net->env, BUT_WRITEFILE, net->fd);
555     }
556   }
557   net->env->partners[net->partner] = NULL;
558   MAGIC_UNSET(net);
559   wms_free(net);
560 }
561 
562 
butRnet_send(ButRnet * net,void * buffer,int len)563 void  butRnet_send(ButRnet *net, void *buffer, int len)  {
564   ButNetMsg  msg;
565 
566   assert(len <= BUTNET_MAXCMD);
567   msg.length = int_stdInt32(len);
568   msg.type = int_stdInt32(BUTNET_USERDATA);
569   memcpy(msg.perType.userData, buffer, len);
570   butRnet_write(net, &msg);
571 }
572 
573 
butRnet_mMove(ButEnv * env,int winId,int lx,int ly,int lw,int lh,ButCur curnum)574 void  butRnet_mMove(ButEnv *env, int winId, int lx,int ly, int lw,int lh,
575 		    ButCur curnum)  {
576   int  i;
577 
578   for (i = 0;  i < env->numPartners;  ++i)  {
579     if (env->partners[i])  {
580       if (butRnet_valid(env->partners[i]) &&
581 	  ((winId != -2) || (env->partners[i]->lWinId != -2)))
582 	butRnet_sendMMove(env->partners[i], winId, lx,ly, lw,lh, curnum);
583     }
584   }
585 }
586 
587 
butRnet_sendMMove(ButRnet * net,int winId,int lx,int ly,int lw,int lh,ButCur curnum)588 static void  butRnet_sendMMove(ButRnet *net, int winId, int lx, int ly,
589 			       int lw, int lh, ButCur curnum)  {
590   ButNetMsg  msg;
591 
592   if (winId == -1)
593     winId = net->lWinId;
594   if (lx == -1)
595     lx = net->lx;
596   if (ly == -1)
597     ly = net->ly;
598   if (lw == -1)
599     lw = net->lw;
600   if (lh == -1)
601     lh = net->lh;
602   if (curnum == -1)
603     curnum = net->lType;
604   net->lWinId = winId;
605   net->lx = lx;
606   net->ly = ly;
607   net->lw = lw;
608   net->lh = lh;
609   net->lType = curnum;
610   if (net->ackNeeded)
611     net->mouseMove = TRUE;
612   else  {
613     msg.length = int_stdInt32(sizeof(msg.perType.mouse));
614     msg.type = int_stdInt32(BUTNET_MOUSE);
615     msg.perType.mouse.context = int_stdInt32(0);
616     msg.perType.mouse.win = int_stdInt32(winId);
617     msg.perType.mouse.x = int_stdInt32(lx);
618     msg.perType.mouse.y = int_stdInt32(ly);
619     msg.perType.mouse.w = int_stdInt32(lw);
620     msg.perType.mouse.h = int_stdInt32(lh);
621     msg.perType.mouse.type = int_stdInt32(curnum);
622     assert((curnum == -1) ||
623 	   (curnum < butCur_bogus));
624     butRnet_write(net, &msg);
625   }
626 }
627 
628 
butRnet_newFlags(ButEnv * env,int butId,uint newFlags)629 void  butRnet_newFlags(ButEnv *env, int butId, uint newFlags)  {
630   int  i;
631   ButNetMsg  msg;
632 
633   if ((butId != -2) && (env->numPartners > 0))  {
634     assert(butId >= 0);
635     assert(butId < env->maxButIds);
636     newFlags = (newFlags & ~(BUT_NETTWITCH|BUT_NETPRESS|BUT_NETKEY)) |
637       ((newFlags & BUT_NETMASK) << BUT_NETSHIFT);
638     msg.length = int_stdInt32(sizeof(msg.perType.newFlags));
639     msg.type = int_stdInt32(BUTNET_NEWFLAGS);
640     msg.perType.newFlags.butId = int_stdInt32(butId);
641     msg.perType.newFlags.newFlags = int_stdInt32(newFlags);
642     for (i = 0;  i < env->numPartners;  ++i)  {
643       if (env->partners[i])
644 	if (butRnet_valid(env->partners[i]))
645 	  butRnet_write(env->partners[i], &msg);
646     }
647   }
648 }
649 
650 
butSpec(ButEnv * env,int butId,void * buf,int bufLen)651 static ButOut  butSpec(ButEnv *env, int butId, void *buf, int bufLen)  {
652   But  *but;
653 
654   but = env->id2But[butId];
655   assert(but->action->netMessage);
656   return(but->action->netMessage(but, buf, bufLen));
657 }
658 
659 
660 #else  /* !HAVE_SOCKETS */
661 
butLnet_create(ButEnv * env,int port,void * packet,ButOut ocallback (ButRnet * net),ButOut callback (ButRnet * net,void * cmd,int cmdLen),ButOut ccallback (ButRnet * net,const char * reason))662 ButLnet  *butLnet_create(ButEnv *env, int port, void *packet,
663 			 ButOut ocallback(ButRnet *net),
664 			 ButOut callback(ButRnet *net, void *cmd, int cmdLen),
665 			 ButOut ccallback(ButRnet *net, const char *reason))  {
666   ButLnet  *net = wms_malloc(sizeof(ButLnet));
667 
668   net->error = TRUE;
669   net->valid = FALSE;
670   net->errNum = EPERM;
671   return(net);
672 }
673 
674 
butRnet_create(ButEnv * env,char * address,int port,void * packet,ButOut ocallback (ButRnet * net),ButOut callback (ButRnet * net,void * cmd,int cmdLen),ButOut ccallback (ButRnet * net,const char * reason))675 ButRnet  *butRnet_create(ButEnv *env, char *address, int port,
676 			 void *packet, ButOut ocallback(ButRnet *net),
677 			 ButOut callback(ButRnet *net, void *cmd, int cmdLen),
678 			 ButOut ccallback(ButRnet *net, const char *reason))  {
679   ButRnet  *net = wms_malloc(sizeof(ButRnet));
680 
681   net->error = TRUE;
682   net->errNum = EPERM;
683   net->state = butRnetState_closed;
684   return(net);
685 }
686 
687 
butLnet_destroy(ButLnet * net)688 void  butLnet_destroy(ButLnet  *net)  { wms_free(net); }
butRnet_destroy(ButRnet * net,char * reason)689 void  butRnet_destroy(ButRnet *net, char *reason)  { wms_free(net); }
butRnet_write(ButRnet * net,ButNetMsg * msg)690 bool  butRnet_write(ButRnet *net, ButNetMsg *msg)  { return(FALSE); }
butRnet_send(ButRnet * net,void * buffer,int len)691 void  butRnet_send(ButRnet *net, void *buffer, int len)  {}
butRnet_mMove(ButEnv * env,int winId,int lx,int ly,int lw,int lh,ButCur curnum)692 void  butRnet_mMove(ButEnv *env, int winId, int lx,int ly, int lw,int lh,
693 		    ButCur curnum)  {}
butRnet_newFlags(ButEnv * env,int butId,uint newFlags)694 void  butRnet_newFlags(ButEnv *env, int butId, uint newFlags)  {}
butRnet_accept(ButRnet * net)695 void  butRnet_accept(ButRnet *net)  {}
696 
697 
698 #endif  /* HAVE_SOCKETS */
699 
700 
but_setId(But * but,int id)701 void  but_setId(But *but, int id)  {
702   ButEnv  *env = but->win->env;
703   int  i;
704 
705   assert(MAGIC(but));
706   if (id >= env->maxButIds)  {
707     But  **newId2But;
708     int  newMaxButIds = (id + 1)*2;
709 
710     newId2But = wms_malloc(newMaxButIds * sizeof(But *));
711     for (i = 0;  i < env->maxButIds;  ++i)
712       newId2But[i] = env->id2But[i];
713     for (;  i < newMaxButIds;  ++i)
714       newId2But[i] = NULL;
715     env->maxButIds = newMaxButIds;
716     if (env->id2But)
717       wms_free(env->id2But);
718     env->id2But = newId2But;
719   }
720   if (but->id != -1)  {
721     assert(but->id < env->maxButIds);
722     env->id2But[id] = NULL;
723   }
724   env->id2But[id] = but;
725   but->id = id;
726 }
727 
728 
butWin_setId(ButWin * win,int id)729 void  butWin_setId(ButWin *win, int id)  {
730   ButEnv  *env = win->env;
731   int  i;
732 
733   assert(MAGIC(win));
734   if (id >= env->maxWinIds)  {
735     ButWin  **newId2Win;
736     int  newMaxWinIds = (id + 1)*2;
737 
738     newId2Win = wms_malloc(newMaxWinIds * sizeof(ButWin *));
739     for (i = 0;  i < env->maxWinIds;  ++i)
740       newId2Win[i] = env->id2Win[i];
741     for (;  i < newMaxWinIds;  ++i)
742       newId2Win[i] = NULL;
743     env->maxWinIds = newMaxWinIds;
744     if (env->id2Win)
745       wms_free(env->id2Win);
746     env->id2Win = newId2Win;
747   }
748   if (win->id != -1)  {
749     assert(win->id < env->maxWinIds);
750     env->id2Win[id] = NULL;
751   }
752   env->id2Win[id] = win;
753   win->id = id;
754 }
755 
756 
butRnet_butSpecSend(But * but,void * buffer,int len)757 void  butRnet_butSpecSend(But *but, void *buffer, int len)  {
758   ButEnv *env;
759   ButNetMsg  msg;
760   int  i;
761 
762   assert(len < BUTNET_MAXCMD - sizeof(StdInt32));
763   if (but->id >= 0)  {
764     env = but->win->env;
765     if (env->numPartners > 0)  {
766       msg.length = int_stdInt32(len + 4);
767       msg.type = int_stdInt32(BUTNET_BUTSPEC);
768       msg.perType.butSpec.butId = int_stdInt32(but->id);
769       if (len > 0)
770 	memcpy(msg.perType.butSpec.butData, buffer, len);
771       for (i = 0;  i < env->numPartners;  ++i)  {
772 	if (env->partners[i])  {
773 	  if (butRnet_valid(env->partners[i]))
774 	    butRnet_write(env->partners[i], &msg);
775 	}
776       }
777     }
778   }
779 }
780 
781 
782 #endif  /* X11_DISP */
783