1 /*
2  * Author:      William Chia-Wei Cheng (bill.cheng@acm.org)
3  *
4  * Copyright (C) 2001-2009, William Chia-Wei Cheng.
5  *
6  * This file may be distributed under the terms of the Q Public License
7  * as defined by Trolltech AS of Norway and appearing in the file
8  * LICENSE.QPL included in the packaging of this file.
9  *
10  * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING
11  * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
13  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  * @(#)$Header: /mm2/home/cvs/bc-src/tgif/wb.c,v 1.45 2011/05/16 16:22:00 william Exp $
19  */
20 
21 #define _INCLUDE_FROM_WB_C_
22 
23 #if (defined(PTHREAD) || defined(HAVE_LIBPTHREAD))
24 #include <pthread.h>
25 #endif /* (defined(PTHREAD) || defined(HAVE_LIBPTHREAD)) */
26 
27 #include "tgifdefs.h"
28 #include "cmdids.h"
29 
30 #ifdef _HAS_STREAMS_SUPPORT
31 #include <stropts.h>
32 #include <sys/types.h>
33 #endif /* _HAS_STREAMS_SUPPORT */
34 #include "rmcast/src/rmcast.h"
35 
36 #include "auxtext.e"
37 #include "chat.e"
38 #include "choice.e"
39 #include "color.e"
40 #include "cmd.e"
41 #include "dialog.e"
42 #include "drawing.e"
43 #include "file.e"
44 #include "font.e"
45 #include "grid.e"
46 #include "http.e"
47 #include "import.e"
48 #include "mark.e"
49 #include "menu.e"
50 #include "msg.e"
51 #include "obj.e"
52 #include "page.e"
53 #include "raster.e"
54 #include "remote.e"
55 #include "rm_intrf.e"
56 #include "ruler.e"
57 #include "scroll.e"
58 #include "select.e"
59 #include "setup.e"
60 #include "stk.e"
61 #include "strtbl.e"
62 #include "tcp.e"
63 #include "util.e"
64 #include "version.e"
65 #include "wb.e"
66 #include "wb_buff.e"
67 #include "wb_seg.e"
68 #include "xpixmap.e"
69 #include "z_intrf.e"
70 
71 struct WhiteBoardRec	gstWBInfo;
72 
73 int	cmdLineNoWhiteBoard=FALSE;
74 int	cmdLineWhiteBoardListenOnly=FALSE;
75 
76 static int	recordCmdLogicalClock=0;
77 static char	recordCmdSenderProcID[MAXSTRING];
78 
79 #ifdef _TGIF_DBG_WB2
80 static int		wb2DebugLevel=0;
81 #endif /* _TGIF_DBG_WB2 */
82 
83 /* =================== Remote Related Functions =================== */
84 
85 static
CleanUpWBSockets()86 void CleanUpWBSockets()
87 {
88    if (gstWBInfo.listening) {
89       if (gstWBInfo.listen_socket != (-1)) {
90          close(gstWBInfo.listen_socket);
91          gstWBInfo.listen_socket = (-1);
92       }
93       if (gstWBInfo.listen_fp != NULL) {
94          fclose(gstWBInfo.listen_fp);
95          gstWBInfo.listen_fp = NULL;
96       }
97       if (gstWBInfo.gz_listen_fp != NULL) {
98          fclose(gstWBInfo.gz_listen_fp);
99          gstWBInfo.gz_listen_fp = NULL;
100       }
101       if (*gstWBInfo.gz_listen_fname != '\0') {
102          unlink(gstWBInfo.gz_listen_fname);
103          *gstWBInfo.gz_listen_fname = '\0';
104       }
105       if (*gstWBInfo.listen_fname != '\0') {
106          unlink(gstWBInfo.listen_fname);
107          *gstWBInfo.listen_fname = '\0';
108       }
109       gstWBInfo.listening = FALSE;
110    }
111    if (gstWBInfo.send_socket != (-1)) {
112       close(gstWBInfo.send_socket);
113       gstWBInfo.send_socket = (-1);
114    }
115    if (gstWBInfo.gz_send_fp != NULL) {
116       fclose(gstWBInfo.gz_send_fp);
117       gstWBInfo.gz_send_fp = NULL;
118    }
119    if (gstWBInfo.send_fp != NULL) {
120       fclose(gstWBInfo.send_fp);
121       gstWBInfo.send_fp = NULL;
122    }
123    if (*gstWBInfo.gz_send_fname != '\0') {
124       unlink(gstWBInfo.gz_send_fname);
125       *gstWBInfo.gz_send_fname = '\0';
126    }
127    if (*gstWBInfo.send_fname != '\0') {
128       unlink(gstWBInfo.send_fname);
129       *gstWBInfo.send_fname = '\0';
130    }
131 }
132 
133 static
CleanUpWBShadowCmds()134 void CleanUpWBShadowCmds()
135 {
136    struct CmdRec *cmd_ptr=NULL;
137    int num_records=0;
138 
139    for (cmd_ptr=gstWBInfo.last_shadow_cmd; cmd_ptr != NULL;
140          cmd_ptr=cmd_ptr->prev) {
141       num_records++;
142    }
143    if (num_records > 0) {
144       struct CmdRec *prev_cmd=NULL;
145       double inc=(100.0/((double)num_records)), percent_start=0.0;
146 
147       ShowInterrupt(1);
148       SaveStatusStrings();
149       for (cmd_ptr=gstWBInfo.last_shadow_cmd; cmd_ptr != NULL; cmd_ptr=prev_cmd,
150             percent_start+=inc) {
151          prev_cmd = cmd_ptr->prev;
152          DeleteARedoRecord(cmd_ptr, percent_start,
153                min(((double)percent_start+inc),((double)100.0)));
154       }
155       RestoreStatusStrings();
156       HideInterrupt();
157    }
158    gstWBInfo.first_shadow_cmd = gstWBInfo.last_shadow_cmd = NULL;
159 }
160 
161 static
CleanUpWBCmds()162 void CleanUpWBCmds()
163 {
164    struct CmdRec *cmd_ptr=NULL;
165    int num_records=0;
166 
167    for (cmd_ptr=gstWBInfo.last_cmd; cmd_ptr != NULL; cmd_ptr=cmd_ptr->prev) {
168       num_records++;
169    }
170    if (num_records > 0) {
171       struct CmdRec *prev_cmd=NULL;
172       double inc=(100.0/((double)num_records)), percent_start=0.0;
173 
174       ShowInterrupt(1);
175       SaveStatusStrings();
176       for (cmd_ptr=gstWBInfo.last_cmd; cmd_ptr != NULL; cmd_ptr=prev_cmd,
177             percent_start+=inc) {
178          prev_cmd = cmd_ptr->prev;
179          DeleteARedoRecord(cmd_ptr, percent_start,
180                min(((double)percent_start+inc),((double)100.0)));
181       }
182       RestoreStatusStrings();
183       HideInterrupt();
184    }
185    gstWBInfo.first_cmd = gstWBInfo.last_cmd = gstWBInfo.cur_cmd = NULL;
186 
187    CleanUpWBShadowCmds();
188 }
189 
190 static
CreateWBListenSocket()191 int CreateWBListenSocket()
192 {
193    gstWBInfo.listening = TRUE;
194 
195    if (MkTempFile(gstWBInfo.listen_fname, sizeof(gstWBInfo.listen_fname),
196          tmpDir, TOOL_NAME) == NULL) {
197       fprintf(stderr, "Fail to create '%s' for deserialization.\n",
198             gstWBInfo.listen_fname);
199       return FALSE;
200    }
201    snprintf(gstWBInfo.gz_listen_fname, sizeof(gstWBInfo.gz_listen_fname),
202          "%s.z", gstWBInfo.listen_fname);
203    if ((gstWBInfo.listen_fp=fopen(gstWBInfo.listen_fname, "w+")) == NULL) {
204       fprintf(stderr, "Fail to create '%s' for deserialization.\n",
205             gstWBInfo.listen_fname);
206       return FALSE;
207    }
208    if ((gstWBInfo.gz_listen_fp=fopen(gstWBInfo.gz_listen_fname, "w+")) ==
209          NULL) {
210       fprintf(stderr, "Fail to create '%s' for deserialization.\n",
211             gstWBInfo.gz_listen_fname);
212       return FALSE;
213    }
214 
215    return TRUE;
216 }
217 
PrintFullIDsOfObjects(psz_prefix)218 void PrintFullIDsOfObjects(psz_prefix)
219    char *psz_prefix;
220 {
221 #ifdef _TGIF_DBG_WB2
222    if (wb2DebugLevel > 0) {
223       struct ObjRec *obj_ptr=NULL;
224       int stacking_order=0;
225 
226       if (psz_prefix != NULL) {
227          if (strcmp(psz_prefix, "\t") == 0) {
228             fprintf(stderr, "\tin PrintFullIDsOfObjects():\n");
229          } else {
230             fprintf(stderr, "%s, in PrintFullIDsOfObjects():\n", psz_prefix);
231          }
232       } else {
233          fprintf(stderr, "In PrintFullIDsOfObjects():\n");
234       }
235       for (obj_ptr=topObj; obj_ptr != NULL; obj_ptr=obj_ptr->next,
236             stacking_order++) {
237          char buf[MAXSTRING], obj_type[MAXSTRING];
238 
239          if (obj_ptr->creator_full_id == NULL) {
240             sprintf(buf, "(NULL)%1d/%s", obj_ptr->id, gszLocalPID);
241          } else {
242             strcpy(buf, obj_ptr->creator_full_id);
243          }
244          switch (obj_ptr->type) {
245          case OBJ_POLY: strcpy(obj_type, "p"); break;
246          case OBJ_BOX: strcpy(obj_type, "b"); break;
247          case OBJ_OVAL: strcpy(obj_type, "o"); break;
248          case OBJ_TEXT:
249             strcpy(obj_type, "t");
250             {
251                MiniLinesInfo *minilines=(&obj_ptr->detail.t->minilines);
252                char *psz=minilines->first->first_block->seg->dyn_str.s;
253                char buf1[MAXSTRING];
254                int len=strlen(psz);
255 
256                if (len > 5) {
257                   char saved_ch=psz[5];
258 
259                   sprintf(buf1, " - \"%s...\"", psz);
260                   psz[5] = saved_ch;
261                } else {
262                   sprintf(buf1, " - \"%s\"", psz);
263                }
264                strcat(buf, buf1);
265             }
266             break;
267          case OBJ_POLYGON: strcpy(obj_type, "g"); break;
268          case OBJ_ARC: strcpy(obj_type, "a"); break;
269          case OBJ_RCBOX: strcpy(obj_type, "rcb"); break;
270          case OBJ_XBM: strcpy(obj_type, "xbm"); break;
271          case OBJ_XPM: strcpy(obj_type, "xpm"); break;
272          case OBJ_GROUP:
273          case OBJ_ICON:
274          case OBJ_SYM:
275          case OBJ_PIN: strcpy(obj_type, "r"); break;
276          }
277          fprintf(stderr, "\t%d/%s:\t%s\n", stacking_order, obj_type, buf);
278       }
279    }
280 #endif /* _TGIF_DBG_WB2 */
281 }
282 
283 
RecvWBData(flag,ppsz_buf,pn_buf_sz)284 int RecvWBData(flag, ppsz_buf, pn_buf_sz)
285    int flag, *pn_buf_sz;
286    char **ppsz_buf;
287 {
288 
289    int retval;
290 
291    retval = buff_rem(gstWBInfo.bd_commands, (void**)ppsz_buf);
292 
293    return retval;
294 }
295 
296 static
ProcessWBInputData(buf)297 void ProcessWBInputData(buf)
298    char *buf;
299    /*
300     * Here the WB input data is in the HTTP data format.
301     * So we use HttpExtractText() to convert the data into
302     *       something that can be handled by ProcessRemoteCmd().
303     * In the future, if the WB input data is binary, this is
304     *       where the conversion takes place.
305     */
306 {
307    char *psz_content=NULL, *psz_content_type=NULL;
308    int content_sz=0;
309 
310    psz_content = HttpExtractText(buf, &content_sz, NULL, &psz_content_type);
311    if (psz_content != NULL) {
312       ProcessRemoteCmd(psz_content_type, psz_content, content_sz);
313       FreeRemoteBuf(psz_content);
314    }
315    if (psz_content_type != NULL) UtilFree(psz_content_type);
316 }
317 
WBHasReadData(pn_flag,pn_retry)318 int WBHasReadData(pn_flag, pn_retry)
319    int *pn_flag, *pn_retry;
320 {
321    /* leave *pn_retry alone */
322 
323    if ((!(gstWBInfo.BlockRemoteCmdDepth <= 1)) && (buff_items(gstWBInfo.bd_commands) > 0) )
324    {
325       /* FIXME fprintf(stderr,"gstWBInfo.BlockRemoteCmdDepth > 1 e existem dados no buffer. (WBHasReadData)\n");
326       exit(1); */
327    }
328 
329    return (gstWBInfo.BlockRemoteCmdDepth <= 1 &&
330          buff_items(gstWBInfo.bd_commands) > 0);
331 }
332 
333 
334 
TryHandleWBInputData()335 void TryHandleWBInputData()
336 {
337    int flag=0, retry=TRUE;
338    char *buf;
339    int buf_sz;
340 
341      while (retry && WBHasReadData(&flag, &retry)) {
342 
343       buf=NULL;
344       buf_sz=0;
345 
346       deserializingFile = TRUE;
347 
348       if (RecvWBData(flag, &buf, &buf_sz)) {
349          ProcessWBInputData(buf);
350          FreeRemoteBuf(buf);
351       }
352       deserializingFile = FALSE;
353      }
354 }
355 
SendWBData(pszWBData,logical_clock)356 int SendWBData(pszWBData, logical_clock)
357    char *pszWBData;
358    int   logical_clock;
359 {
360    int    nPackets1, i;
361    struct SegmentationPack *pack1;
362 
363 #ifdef DEBUG
364    fprintf(stderr,"Mensagem enviada:\n%s\n", pszWBData);
365 #endif
366 
367    pack1 = Segment( pszWBData, strlen(pszWBData), gszLocalPID, logical_clock, &nPackets1 );
368 
369    for( i = 0; i < nPackets1; i++ )
370    {
371       RM_sendto(gstWBInfo.MCastSock, (char*)&pack1[i], sizeof(struct SegmentationPack));
372    }
373    free( pack1 );
374 
375 #ifdef _TGIF_DBG_WB2
376    fprintf(stderr, "SendWBData(), pid = %ld\n", gstWBInfo.pid);
377 #endif /* _TGIF_DBG_WB2 */
378 
379    return TRUE;
380 }
381 
382 /* =================== Cmd Related Functions =================== */
383 
384 static
SaveCmd(FP,CmdType,psi)385 int SaveCmd(FP, CmdType, psi)
386    FILE *FP;
387    int CmdType;
388    SerializationInfo *psi;
389 {
390    struct SelRec *sel_ptr=NULL;
391    int count=0;
392 
393    /*
394     * This part should work now!
395     *
396     * if (recordCmdIncludeTgifObj) {
397     *    sprintf(gszMsgBox, "%s.\n%s %s.\n\n%s %s.",
398     *          "Warning: recordCmdIncludeTgifObj is TRUE in SaveCmd()",
399     *          TOOL_NAME, "WhiteBoard may crash",
400     *          "Please try to reproduce this error and send bug report to",
401     *          authorEmailString);
402     *    MsgBox(gszMsgBox, TOOL_NAME, STOP_MB);
403     *    return FALSE;
404     * } else
405     */
406    if (CmdType == CMD_GOTO_PAGE) {
407       /*
408        * GotoPage() is disabled for _TGIF_WB2.
409        */
410       return FALSE;
411    }
412    if (fprintf(FP, "cmd(%1d,", CmdType) == EOF) {
413       writeFileFailed = TRUE;
414    }
415    if (CmdType == CMD_MOVE) {
416       if (fprintf(FP, "%1d,%1d,",
417             psi->subcmd->detail.move.dx, psi->subcmd->detail.move.dy) == EOF) {
418          writeFileFailed = TRUE;
419       }
420    } else if (CmdType == CMD_WB_CLEARALL) {
421       if (fprintf(FP, "%1d,%.3f,",
422             psi->subcmd->detail.clearall.page_style,
423             psi->subcmd->detail.clearall.print_mag) == EOF) {
424          writeFileFailed = TRUE;
425       }
426    } else if (CmdType == CMD_WB_SLIDESHOW) {
427       if (fprintf(FP, "%1d,",
428             psi->subcmd->detail.slideshow.into_slideshow) ==
429             EOF) {
430          writeFileFailed = TRUE;
431       }
432    } else if (CmdType == CMD_CHAT_A_LINE) {
433       if (fprintf(FP, "%1d,'", psi->subcmd->detail.chat.type) == EOF) {
434          writeFileFailed = TRUE;
435       }
436       SaveString(FP, psi->subcmd->detail.chat.nick_name);
437       if (fprintf(FP, "','%s',%1d,'%s',",
438             psi->subcmd->detail.chat.tfi.color_str,
439             psi->subcmd->detail.chat.tfi.font_style,
440             psi->subcmd->detail.chat.encoding) == EOF) {
441          writeFileFailed = TRUE;
442       }
443       if (fprintf(FP, "\"") == EOF) writeFileFailed = TRUE;
444       SaveString(FP, psi->subcmd->detail.chat.buf);
445       if (fprintf(FP, "\",") == EOF) writeFileFailed = TRUE;
446    }
447    if (fprintf(FP, "%1d,%1d,%1d,\"%s\").\n",
448          psi->include_tgif_obj, psi->new_colormap, psi->logical_clock,
449          psi->sender_process_id) == EOF) {
450       writeFileFailed = TRUE;
451    }
452    /* Lamport's Algorithm increments logical_clock */
453    gstWBInfo.logical_clock++;
454 
455    if (psi->bot_before != NULL) {
456       if (fprintf(FP, "before_image(%1d,[\n", psi->count_before) == EOF) {
457          writeFileFailed = TRUE;
458       }
459       for (count=0, sel_ptr=psi->top_before; sel_ptr != NULL;
460             sel_ptr=sel_ptr->next, count++) {
461          struct ObjRec *obj_ptr=sel_ptr->obj;
462          char buf[MAXSTRING];
463 
464          if (psi->pos_before_has_ids) {
465             sprintf(buf, "%s", ((char**)psi->pos_before)[count]);
466          } else {
467             if (obj_ptr->creator_full_id == NULL) {
468                sprintf(buf, "%1d/%s", obj_ptr->id, psi->sender_process_id);
469             } else {
470                strcpy(buf, obj_ptr->creator_full_id);
471             }
472          }
473          if (fprintf(FP, "\t\"") == EOF) writeFileFailed = TRUE;
474          SaveString(FP, buf);
475          if (sel_ptr->next == NULL) {
476             if (fprintf(FP, "\"\n") == EOF) writeFileFailed = TRUE;
477          } else {
478             if (fprintf(FP, "\",\n") == EOF) writeFileFailed = TRUE;
479          }
480       }
481       if (fprintf(FP, "]).\n") == EOF) writeFileFailed = TRUE;
482    }
483    if (psi->bot_sel != NULL) {
484       struct SelRec *sel_ptr;
485       int *stacking_pos=NULL, stacking_count=0;
486 
487       sel_ptr = PrepareStackingInfo(psi->top_sel,
488             psi->bot_sel, psi->num_objs, FALSE,
489             &stacking_pos, &stacking_count, NULL);
490       if (sel_ptr == NULL && stacking_count == psi->num_objs) {
491          if (fprintf(FP, "after_positions(%1d,[\n",
492                psi->num_objs) == EOF) {
493             writeFileFailed = TRUE;
494          }
495          for (count=0, sel_ptr=psi->top_sel;
496                count < stacking_count && sel_ptr != NULL;
497                count++, sel_ptr=sel_ptr->next) {
498             char buf[MAXSTRING];
499 
500             sprintf(buf, "%1d", stacking_pos[count]);
501             if (fprintf(FP, "\t") == EOF) writeFileFailed = TRUE;
502             SaveString(FP, buf);
503             if (sel_ptr->next == NULL) {
504                if (fprintf(FP, "\n") == EOF) writeFileFailed = TRUE;
505             } else {
506                if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
507             }
508          }
509          if (fprintf(FP, "]).\n") == EOF) writeFileFailed = TRUE;
510 
511          if (fprintf(FP, "after_image(%1d,[\n", psi->num_objs) ==
512                EOF) {
513             writeFileFailed = TRUE;
514          }
515          for (count=0, sel_ptr=psi->top_sel; sel_ptr != NULL;
516                sel_ptr=sel_ptr->next, count++) {
517             SaveObj(FP, sel_ptr->obj, 1);
518             if (sel_ptr->next == NULL) {
519                if (fprintf(FP, "\n") == EOF) writeFileFailed = TRUE;
520             } else {
521                if (fprintf(FP, ",\n") == EOF) writeFileFailed = TRUE;
522             }
523          }
524          if (fprintf(FP, "]).\n") == EOF) writeFileFailed = TRUE;
525       }
526       if (stacking_pos != NULL) free(stacking_pos);
527    }
528    return TRUE;
529 }
530 
531 static
PrepareExtendedSerializationInfo(CmdPtr,psi)532 void PrepareExtendedSerializationInfo(CmdPtr, psi)
533    struct CmdRec *CmdPtr;
534    SerializationInfo *psi;
535 {
536    psi->subcmd = CmdPtr->subcmd;
537    psi->top_sel = NULL; /* not used */
538    psi->bot_sel = NULL; /* not used */
539    psi->num_objs = 0; /* not used */
540 
541    psi->include_tgif_obj = CmdPtr->include_tgif_obj;
542    psi->new_colormap = CmdPtr->new_colormap;
543    psi->logical_clock = CmdPtr->logical_clock;
544    psi->sender_process_id = CmdPtr->sender_process_id;
545 
546    psi->top_before = CmdPtr->top_before;
547    psi->bot_before = CmdPtr->bot_before;
548    psi->pos_before = CmdPtr->pos_before;
549    psi->count_before = CmdPtr->count_before;
550    psi->pos_before_has_ids = CmdPtr->pos_before_has_ids;
551 }
552 
553 static
SaveExtendedCmd(FP,CmdPtr,psi)554 int SaveExtendedCmd(FP, CmdPtr, psi)
555    FILE *FP;
556    struct CmdRec *CmdPtr;
557    SerializationInfo *psi;
558 {
559    if (CmdPtr->type == CMD_GOTO_PAGE) {
560       /*
561        * GotoPage() is disabled for _TGIF_WB2.
562        */
563       return FALSE;
564    } else if (CmdPtr->type == CMD_CHAT_A_LINE) {
565       /*
566        * intentionally forget what has been chatted
567        */
568       return FALSE;
569    }
570    if (CmdPtr->serialization_buf == NULL) {
571       fprintf(stderr, "serialization_buf is NULL\n");
572       return FALSE;
573    }
574 #ifdef NOT_DEFINED
575    /* this is replaced by simply printing CmdPtr->serialization_buf */
576    if (fprintf(FP, "cmdx(%1d,%1d,", CmdPtr->type, CmdPtr->undone) == EOF) {
577       writeFileFailed = TRUE;
578    }
579    if (CmdPtr->type == CMD_MOVE) {
580       if (fprintf(FP, "%1d,%1d,",
581             CmdPtr->subcmd->detail.move.dx,
582             CmdPtr->subcmd->detail.move.dy) == EOF) {
583          writeFileFailed = TRUE;
584       }
585    } else if (CmdPtr->type == CMD_WB_CLEARALL) {
586       if (fprintf(FP, "%1d,%.3f,",
587             CmdPtr->subcmd->detail.clearall.page_style,
588             CmdPtr->subcmd->detail.clearall.print_mag) == EOF) {
589          writeFileFailed = TRUE;
590       }
591    } else if (CmdPtr->type == CMD_WB_SLIDESHOW) {
592       if (fprintf(FP, "%1d,",
593             CmdPtr->subcmd->detail.slideshow.into_slideshow) == EOF) {
594          writeFileFailed = TRUE;
595       }
596    } else if (CmdPtr->type == CMD_CHAT_A_LINE) {
597       /* intentionally forget what has been chatted */
598       return FALSE;
599    }
600    if (fprintf(FP, "%1d,%1d,%1d,\"%s\",%1d).\n",
601          CmdPtr->include_tgif_obj, CmdPtr->new_colormap, CmdPtr->logical_clock,
602          CmdPtr->sender_process_id, CmdPtr->undone) == EOF) {
603       writeFileFailed = TRUE;
604    }
605 #endif /* NOT_DEFINED */
606    if (fprintf(FP, "%s", CmdPtr->serialization_buf) == EOF) {
607       writeFileFailed = TRUE;
608    }
609    return TRUE;
610 }
611 
612 static
SaveExtendedCmdInfo(FP,nNumCmds,nCurCmdPos)613 int SaveExtendedCmdInfo(FP, nNumCmds, nCurCmdPos)
614    FILE *FP;
615    int nNumCmds, nCurCmdPos;
616 {
617    if (fprintf(FP, "cmdxinfo(%1d,%1d).\n", nNumCmds, nCurCmdPos) == EOF) {
618       writeFileFailed = TRUE;
619    }
620    return TRUE;
621 }
622 
623 #ifdef _TGIF_DBG_WB2
624 static
DebugDumpCmd(psz_prefix,cmd_type,logical_clock,psz_process_id)625 void DebugDumpCmd(psz_prefix, cmd_type, logical_clock, psz_process_id)
626    char *psz_prefix, *psz_process_id;
627    int cmd_type, logical_clock;
628 {
629    if (psz_prefix == NULL) {
630       fprintf(stderr, "cmd(%1d,%1d,\"%s\")\n", cmd_type, logical_clock,
631             psz_process_id);
632    } else {
633       fprintf(stderr, "%s, cmd(%1d,%1d,\"%s\")\n", psz_prefix, cmd_type,
634             logical_clock, psz_process_id);
635    }
636 }
637 #endif /* _TGIF_DBG_WB2 */
638 
SerializeCmd(CmdType,psi,pnAssignedLogicalClock,ppszPlainWBData,pnPlainWBDataSz)639 char *SerializeCmd(CmdType, psi, pnAssignedLogicalClock, ppszPlainWBData,
640       pnPlainWBDataSz)
641    int CmdType, *pnAssignedLogicalClock, *pnPlainWBDataSz;
642    SerializationInfo *psi;
643    char **ppszPlainWBData;
644 {
645    char *buf=NULL, header[MAXSTRING<<1];
646    int content_sz=0, ok=TRUE, header_sz=0, do_deflate=TRUE;
647    long loc_sec=0L, loc_msec=0L;
648 
649    if (HasZlibSupport()) {
650 #ifdef _TGIF_DBG_WB2
651       do_deflate = FALSE;
652 #endif /* _TGIF_DBG_WB2 */
653    } else {
654       do_deflate = FALSE;
655    }
656    if (gstWBInfo.send_fp == NULL || gstWBInfo.gz_send_fp == NULL) {
657       sprintf(gszMsgBox, "Cannot open '%s' or '%s'.\n\nSerialization aborted.",
658             gstWBInfo.send_fname, gstWBInfo.gz_send_fname);
659       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
660       return NULL;
661    }
662    *pnAssignedLogicalClock = gstWBInfo.logical_clock;
663 
664    rewind(gstWBInfo.send_fp);
665    writeFileFailed = FALSE;
666 
667    UtilGetMilliSecTime(&loc_sec, &loc_msec);
668    if (fprintf(gstWBInfo.send_fp, "%%TGWB begin - %ld.%ld\n",
669          loc_sec, loc_msec) == EOF) {
670       writeFileFailed = TRUE;
671    }
672    Save(gstWBInfo.send_fp, NULL, 0, 1);
673    ok = SaveCmd(gstWBInfo.send_fp, CmdType, psi);
674    /* gstWBInfo.logical_clock has been incremented in SaveCmd() */
675 
676    if (fprintf(gstWBInfo.send_fp, "%%TGWB end - %ld.%ld\n",
677          loc_sec, loc_msec) == EOF) {
678       writeFileFailed = TRUE;
679    }
680    if (writeFileFailed) {
681       FailToWriteFileMessage(gstWBInfo.send_fname);
682       return NULL;
683    }
684    if (!ok) {
685       return NULL;
686    }
687    content_sz = (int)ftell(gstWBInfo.send_fp);
688    /*
689     * From: <PID>:<IP>\r\n
690     * Content-Type: application/x-tgif-cmd\r\n
691     * Content-Length: <LENGTH>\r\n
692     * \r\n
693     * <DATA of size LENGTH>
694     */
695    if (do_deflate && HasZlibSupport()) {
696       int rc=0;
697       char *new_buf=NULL;
698 
699       rewind(gstWBInfo.send_fp);
700       new_buf = (char*)malloc((content_sz+1)*sizeof(char));
701       if (new_buf == NULL) FailAllocMessage();
702       if (fread(new_buf, sizeof(char), content_sz, gstWBInfo.send_fp) !=
703             content_sz) {
704 #ifdef _TGIF_DBG_WB2
705          fprintf(stderr, "Failed to read %1d bytes in SerializeCmd().\n",
706                content_sz);
707          fflush(stderr);
708 #endif /* _TGIF_DBG_WB2 */
709          do_deflate = FALSE;
710       } else {
711          new_buf[content_sz] = '\0';
712          *pnPlainWBDataSz = content_sz+1;
713          *ppszPlainWBData = new_buf;
714 
715          if (!DoDeflate(gstWBInfo.send_fp, NULL, content_sz,
716                gstWBInfo.gz_send_fp, TRUE, TRUE, &rc)) {
717             ZlibError(rc, TRUE);
718             do_deflate = FALSE;
719          } else {
720             content_sz = (int)ftell(gstWBInfo.gz_send_fp);
721          }
722       }
723    }
724    if (do_deflate) {
725       sprintf(header, "%s%s\r\n%s%s\r\n%s%1d\r\n\r\n",
726             "From: ", gszLocalPID,
727             "Content-Type: ", "application/x-tgif-cmd-z",
728             "Content-Length: ", content_sz);
729       header_sz = strlen(header);
730       buf = (char*)malloc((header_sz+content_sz+1)*sizeof(char));
731       if (buf == NULL) FailAllocMessage();
732       strcpy(buf, header);
733       rewind(gstWBInfo.gz_send_fp);
734       if (fread(&buf[header_sz], sizeof(char), content_sz,
735             gstWBInfo.gz_send_fp) != content_sz) {
736          sprintf(gszMsgBox, "Error in reading '%s'.\n\nSerialization aborted.",
737                gstWBInfo.gz_send_fname);
738          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
739 
740          UtilFree(buf);
741          return NULL;
742       }
743    } else {
744       sprintf(header, "%s%s\r\n%s%s\r\n%s%1d\r\n\r\n",
745             "From: ", gszLocalPID,
746             "Content-Type: ", "application/x-tgif-cmd",
747             "Content-Length: ", content_sz);
748       header_sz = strlen(header);
749       buf = (char*)malloc((header_sz+content_sz+1)*sizeof(char));
750       if (buf == NULL) FailAllocMessage();
751       strcpy(buf, header);
752       rewind(gstWBInfo.send_fp);
753       if (fread(&buf[header_sz], sizeof(char), content_sz, gstWBInfo.send_fp) !=
754             content_sz) {
755          sprintf(gszMsgBox, "Error in reading '%s'.\n\nSerialization aborted.",
756                gstWBInfo.send_fname);
757          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
758 
759          UtilFree(buf);
760          return NULL;
761       }
762    }
763    buf[header_sz+content_sz] = '\0';
764 #ifdef _TGIF_DBG_WB2
765    if (wb2DebugLevel == 0) {
766       fprintf(stderr, "Sending %1d bytes, pid = %ld!\n", header_sz+content_sz+2,
767             gstWBInfo.pid);
768    } else {
769       fprintf(stderr, "===========================\n");
770       if (do_deflate) {
771          fprintf(stderr, "%s", header);
772          fprintf(stderr, "[content not displayed] ...\n");
773       } else {
774          fprintf(stderr, "%s", buf);
775       }
776       fprintf(stderr, "===========================\n");
777       fprintf(stderr, "Sending %1d bytes, pid = %ld!\n", header_sz+content_sz+2,
778             gstWBInfo.pid);
779    }
780    DebugDumpCmd(">>> In SerializeCmd()",
781          CmdType, *pnAssignedLogicalClock, gszLocalPID);
782    PrintFullIDsOfObjects("In SerializeCmd()");
783 #endif /* _TGIF_DBG_WB2 */
784 
785    return buf;
786 }
787 
SerializeFreeBuf(pszWBData)788 void SerializeFreeBuf(pszWBData)
789    char *pszWBData;
790 {
791    UtilFree(pszWBData);
792 }
793 
794 static struct CmdRec gstDeserializeCmd;
795 static struct SubCmdRec *gpDeserializeSubCmd=NULL;
796 
797 static char **gppszBeforeImage=NULL;
798 static int gnBeforeImageCount=0;
799 
800 static int *gpnAfterPositions=NULL;
801 static int gnAfterPositionsCount=0;
802 
803 static int seenCmdXInfo=FALSE;
804 
805 static
CleanUpDeserializeCmd()806 void CleanUpDeserializeCmd()
807 {
808    if (gpDeserializeSubCmd != NULL) free(gpDeserializeSubCmd);
809    memset(&gstDeserializeCmd, 0, sizeof(struct CmdRec));
810    gpDeserializeSubCmd = NULL;
811 }
812 
813 static
InitDeserializeCmd()814 int InitDeserializeCmd()
815 {
816    gpDeserializeSubCmd = (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
817    if (gpDeserializeSubCmd == NULL) FailAllocMessage();
818    memset(gpDeserializeSubCmd, 0, sizeof(struct SubCmdRec));
819    memset(&gstDeserializeCmd, 0, sizeof(struct CmdRec));
820    gstDeserializeCmd.subcmd = gpDeserializeSubCmd;
821 
822    return TRUE;
823 }
824 
825 static
DoDeserializationCleanUp()826 void DoDeserializationCleanUp()
827 {
828    switch (gstDeserializeCmd.type) {
829    case CMD_WB_CLEARALL: break;
830    case CMD_CHAT_A_LINE:
831       UtilFree(gpDeserializeSubCmd->detail.chat.buf);
832       break;
833    case CMD_WB_SLIDESHOW: break;
834    default: break;
835    }
836    memset(gpDeserializeSubCmd, 0, sizeof(struct SubCmdRec));
837    memset(&gstDeserializeCmd, 0, sizeof(gstDeserializeCmd));
838    gstDeserializeCmd.subcmd = gpDeserializeSubCmd;
839    gstDeserializeCmd.type = INVALID;
840 }
841 
842 static
CleanUpBeforeImage()843 void CleanUpBeforeImage()
844 {
845    if (gppszBeforeImage != NULL) {
846       int i;
847 
848       for (i=0; i < gnBeforeImageCount; i++) {
849          if (gppszBeforeImage[i] != NULL) {
850             UtilFree(gppszBeforeImage[i]);
851          } else {
852             break;
853          }
854       }
855       free(gppszBeforeImage);
856    }
857    gppszBeforeImage = NULL;
858    gnBeforeImageCount = 0;
859 }
860 
861 static
CleanUpAfterPositions()862 void CleanUpAfterPositions()
863 {
864    if (gpnAfterPositions != NULL) free(gpnAfterPositions);
865    gpnAfterPositions = NULL;
866    gnAfterPositionsCount = 0;
867 }
868 
869 static
DeserializationCleanUp()870 void DeserializationCleanUp()
871 {
872    DoDeserializationCleanUp();
873    CleanUpBeforeImage();
874    CleanUpAfterPositions();
875 }
876 
877 static
ResetDeserializeCmd()878 void ResetDeserializeCmd()
879 {
880    recordCmdIncludeTgifObj = FALSE;
881    recordCmdUsesNewColormap = FALSE;
882 
883    memset(&gstDeserializeCmd, 0, sizeof(gstDeserializeCmd));
884    gstDeserializeCmd.subcmd = gpDeserializeSubCmd;
885    gstDeserializeCmd.type = INVALID;
886    gppszBeforeImage = NULL;
887    gpnAfterPositions = NULL;
888    gnBeforeImageCount = gnAfterPositionsCount = 0;
889 }
890 
ReadExtendedCmd(FP,Inbuf)891 int ReadExtendedCmd(FP, Inbuf)
892    FILE *FP;
893    char *Inbuf;
894 {
895    char *c_ptr=NULL;
896 
897    c_ptr = FindChar((int)'(', Inbuf);
898    InitScan(c_ptr, "\t\n, ()");
899    if (GETINT("cmdx", gstDeserializeCmd.type, "cmd_type") == INVALID ||
900        GETINT("cmdx", gstDeserializeCmd.undone, "undone") == INVALID) {
901       return FALSE;
902    }
903    if (gstDeserializeCmd.type == INVALID) {
904       return FALSE;
905    } else if (gstDeserializeCmd.type == CMD_GOTO_PAGE) {
906       return FALSE;
907    } else if (gstDeserializeCmd.type == CMD_WB_CLEARALL) {
908       int page_style=PORTRAIT;
909       float print_mag=(float)100.0;
910 
911       if (GETINT("cmdx", page_style, "page_style") == INVALID ||
912           GETFLT("cmdx", print_mag, "print_mag") == INVALID) {
913          return FALSE;
914       }
915       gpDeserializeSubCmd->detail.clearall.page_style = page_style;
916       gpDeserializeSubCmd->detail.clearall.print_mag = print_mag;
917    } else if (gstDeserializeCmd.type == CMD_WB_SLIDESHOW) {
918       int into_slideshow=FALSE;
919 
920       if (GETINT("cmdx", into_slideshow, "into_slideshow") == INVALID) {
921          return FALSE;
922       }
923       gpDeserializeSubCmd->detail.slideshow.into_slideshow = into_slideshow;
924    } else if (gstDeserializeCmd.type == CMD_CHAT_A_LINE) {
925       char nick_name[MAXSTRING], color_str[40], font_str[MAXSTRING];
926       char encoding[MAXSTRING];
927       int chat_type=FALSE, font_style=0, new_alloc=0;
928       struct DynStrRec dyn_str;
929 
930       memset(&dyn_str, 0, sizeof(struct DynStrRec));
931       *nick_name = *color_str = *font_str = *encoding = '\0';
932 
933       if (GETINT("cmdx", chat_type,      "type") == INVALID ||
934           GETSTR("cmdx", nick_name,      "nick_name") == INVALID ||
935           GETSTR("cmdx", color_str,      "color_str") == INVALID ||
936           GETINT("cmdx", font_style,     "font_style") == INVALID ||
937           GETSTR("cmdx", encoding,       "encoding") == INVALID ||
938           GETDYN("cmdx", dyn_str, "buf") == INVALID) {
939          return FALSE;
940       }
941       UtilRemoveQuotes(nick_name);
942       UtilRemoveQuotes(color_str);
943       UtilRemoveQuotes(encoding);
944 
945       gpDeserializeSubCmd->detail.chat.tfi.color_index =
946             QuickFindColorIndex(NULL, color_str, &new_alloc, TRUE);
947       UtilStrCpyN(gpDeserializeSubCmd->detail.chat.tfi.color_str,
948             sizeof(gpDeserializeSubCmd->detail.chat.tfi.color_str),
949             colorMenuItems[gpDeserializeSubCmd->detail.chat.tfi.color_index]);
950 
951       gpDeserializeSubCmd->detail.chat.tfi.font_style = font_style;
952       gpDeserializeSubCmd->detail.chat.type = chat_type;
953       UtilStrCpyN(gpDeserializeSubCmd->detail.chat.nick_name,
954             sizeof(gpDeserializeSubCmd->detail.chat.nick_name), nick_name);
955       UtilStrCpyN(gpDeserializeSubCmd->detail.chat.encoding,
956             sizeof(gpDeserializeSubCmd->detail.chat.encoding), encoding);
957       gpDeserializeSubCmd->detail.chat.buf = dyn_str.s;
958       dyn_str.s = NULL;
959    } else if (gstDeserializeCmd.type == CMD_MOVE) {
960       int dx=0, dy=0;
961 
962       if (GETINT("cmdx", dx, "dx") == INVALID ||
963           GETINT("cmdx", dy, "dy") == INVALID) {
964          return FALSE;
965       }
966       gpDeserializeSubCmd->detail.move.dx = dx;
967       gpDeserializeSubCmd->detail.move.dy = dy;
968    }
969    *recordCmdSenderProcID = '\0';
970    if (GETINT("cmdx", recordCmdIncludeTgifObj, "include_tgif_obj")==INVALID ||
971        GETINT("cmdx", recordCmdUsesNewColormap, "use_new_colormap")==INVALID ||
972        GETINT("cmdx", recordCmdLogicalClock, "logical_clock")==INVALID ||
973        GETSTR("cmdx", recordCmdSenderProcID, "sender_process_id")==INVALID ||
974        GETINT("cmdx", gstDeserializeCmd.undone, "undone")==INVALID) {
975       return FALSE;
976    }
977    UtilRemoveQuotes(recordCmdSenderProcID);
978 
979    return TRUE;
980 }
981 
ReadExtendedCmdInfo(FP,Inbuf)982 int ReadExtendedCmdInfo(FP, Inbuf)
983    FILE *FP;
984    char *Inbuf;
985 {
986    char *c_ptr=NULL;
987    int num_cmds=0, cur_cmd_pos=0;
988 
989    c_ptr = FindChar((int)'(', Inbuf);
990    InitScan(c_ptr, "\t\n, ()");
991    if (GETINT("cmdxinfo", num_cmds, "num_cmds") == INVALID ||
992        GETINT("cmdxinfo", cur_cmd_pos, "cur_cmd_pos") == INVALID) {
993       return FALSE;
994    }
995    seenCmdXInfo = TRUE;
996 
997    return TRUE;
998 }
999 
ReadCmd(FP,Inbuf)1000 int ReadCmd(FP, Inbuf)
1001    FILE *FP;
1002    char *Inbuf;
1003 {
1004    char *c_ptr=NULL;
1005 
1006    ResetDeserializeCmd();
1007 
1008    c_ptr = FindChar((int)'(', Inbuf);
1009    InitScan(c_ptr, "\t\n, ()");
1010    if (GETINT("cmd", gstDeserializeCmd.type, "cmd_type") == INVALID) {
1011       return FALSE;
1012    }
1013    if (gstDeserializeCmd.type == INVALID) {
1014       return FALSE;
1015    } else if (gstDeserializeCmd.type == CMD_GOTO_PAGE) {
1016       return FALSE;
1017    } else if (gstDeserializeCmd.type == CMD_WB_CLEARALL) {
1018       int page_style=PORTRAIT;
1019       float print_mag=(float)100.0;
1020 
1021       if (GETINT("cmd", page_style, "page_style") == INVALID ||
1022           GETFLT("cmd", print_mag, "print_mag") == INVALID) {
1023          return FALSE;
1024       }
1025       gpDeserializeSubCmd->detail.clearall.page_style = page_style;
1026       gpDeserializeSubCmd->detail.clearall.print_mag = print_mag;
1027    } else if (gstDeserializeCmd.type == CMD_WB_SLIDESHOW) {
1028       int into_slideshow=FALSE;
1029 
1030       if (GETINT("cmd", into_slideshow, "into_slideshow") == INVALID) {
1031          return FALSE;
1032       }
1033       gpDeserializeSubCmd->detail.slideshow.into_slideshow = into_slideshow;
1034    } else if (gstDeserializeCmd.type == CMD_CHAT_A_LINE) {
1035       char nick_name[MAXSTRING], color_str[40], font_str[MAXSTRING];
1036       char encoding[MAXSTRING];
1037       int chat_type=FALSE, font_style=0, new_alloc=0;
1038       struct DynStrRec dyn_str;
1039 
1040       memset(&dyn_str, 0, sizeof(struct DynStrRec));
1041       *nick_name = *color_str = *font_str = *encoding = '\0';
1042 
1043       if (GETINT("cmd", chat_type,      "type") == INVALID ||
1044           GETSTR("cmd", nick_name,      "nick_name") == INVALID ||
1045           GETSTR("cmd", color_str,      "color_str") == INVALID ||
1046           GETINT("cmd", font_style,     "font_style") == INVALID ||
1047           GETSTR("cmd", encoding,       "encoding") == INVALID ||
1048           GETDYN("cmd", dyn_str, "buf") == INVALID) {
1049          return FALSE;
1050       }
1051       UtilRemoveQuotes(nick_name);
1052       UtilRemoveQuotes(color_str);
1053       UtilRemoveQuotes(encoding);
1054 
1055       gpDeserializeSubCmd->detail.chat.tfi.color_index =
1056             QuickFindColorIndex(NULL, color_str, &new_alloc, TRUE);
1057       UtilStrCpyN(gpDeserializeSubCmd->detail.chat.tfi.color_str,
1058             sizeof(gpDeserializeSubCmd->detail.chat.tfi.color_str),
1059             colorMenuItems[gpDeserializeSubCmd->detail.chat.tfi.color_index]);
1060 
1061       gpDeserializeSubCmd->detail.chat.tfi.font_style = font_style;
1062       gpDeserializeSubCmd->detail.chat.type = chat_type;
1063       UtilStrCpyN(gpDeserializeSubCmd->detail.chat.nick_name,
1064             sizeof(gpDeserializeSubCmd->detail.chat.nick_name), nick_name);
1065       UtilStrCpyN(gpDeserializeSubCmd->detail.chat.encoding,
1066             sizeof(gpDeserializeSubCmd->detail.chat.encoding), encoding);
1067       gpDeserializeSubCmd->detail.chat.buf = dyn_str.s;
1068       dyn_str.s = NULL;
1069    } else if (gstDeserializeCmd.type == CMD_MOVE) {
1070       int dx=0, dy=0;
1071 
1072       if (GETINT("cmd", dx, "dx") == INVALID ||
1073           GETINT("cmd", dy, "dy") == INVALID) {
1074          return FALSE;
1075       }
1076       gpDeserializeSubCmd->detail.move.dx = dx;
1077       gpDeserializeSubCmd->detail.move.dy = dy;
1078    }
1079    *recordCmdSenderProcID = '\0';
1080    if (GETINT("cmd", recordCmdIncludeTgifObj, "include_tgif_obj") == INVALID ||
1081        GETINT("cmd", recordCmdUsesNewColormap, "use_new_colormap") == INVALID ||
1082        GETINT("cmd", recordCmdLogicalClock, "logical_clock") == INVALID ||
1083        GETSTR("cmd", recordCmdSenderProcID, "sender_process_id") == INVALID) {
1084       return FALSE;
1085    }
1086    UtilRemoveQuotes(recordCmdSenderProcID);
1087    return TRUE;
1088 }
1089 
ReadBeforeImage(FP,Inbuf)1090 int ReadBeforeImage(FP, Inbuf)
1091    FILE *FP;
1092    char *Inbuf;
1093 {
1094    char *c_ptr, *line;
1095    int index=0, ok=TRUE;
1096 
1097    c_ptr = FindChar((int)'(', Inbuf);
1098    InitScan(c_ptr, "\t\n, ");
1099    if (GETINT("before_image", gnBeforeImageCount, "before_image_count") ==
1100          INVALID) {
1101       return FALSE;
1102    }
1103    if (gnBeforeImageCount > 0) {
1104       gppszBeforeImage = (char**)malloc(gnBeforeImageCount*sizeof(char*));
1105       if (gppszBeforeImage == NULL) FailAllocMessage();
1106       memset(gppszBeforeImage, 0, gnBeforeImageCount*sizeof(char*));
1107    }
1108    index = 0;
1109    while ((line=UtilGetALine(FP)) != NULL) {
1110       char full_id[MAXSTRING];
1111 
1112       scanLineNum++;
1113       if (*line == ']') {
1114          free(line);
1115          break;
1116       }
1117       if (index >= gnBeforeImageCount) {
1118          fprintf(stderr, "Warning: too many lines in before_image.\n");
1119          free(line);
1120          break;
1121       }
1122       c_ptr = FindChar((int)'"', line);
1123       c_ptr = ParseStr(c_ptr, (int)'"', full_id, sizeof(full_id));
1124       if (c_ptr == NULL) {
1125          ok = FALSE;
1126          free(line);
1127          break;
1128       }
1129       gppszBeforeImage[index] = UtilStrDup(full_id);
1130       if (gppszBeforeImage[index] == NULL) FailAllocMessage();
1131       index++;
1132       free(line);
1133    }
1134    if (ok && index < gnBeforeImageCount) {
1135       fprintf(stderr, "Warning: too few lines in before_image.\n");
1136       ok = FALSE;
1137    }
1138    if (!ok) {
1139       CleanUpBeforeImage();
1140    }
1141    return ok;
1142 }
1143 
ReadAfterPositions(FP,Inbuf)1144 int ReadAfterPositions(FP, Inbuf)
1145    FILE *FP;
1146    char *Inbuf;
1147 {
1148    char *c_ptr, *line;
1149    int index=0, ok=TRUE;
1150 
1151    c_ptr = FindChar((int)'(', Inbuf);
1152    InitScan(c_ptr, "\t\n, ");
1153    if (GETINT("after_positions", gnAfterPositionsCount,
1154          "after_positions_count") == INVALID) {
1155       return FALSE;
1156    }
1157    if (gnAfterPositionsCount > 0) {
1158       gpnAfterPositions = (int*)malloc(gnAfterPositionsCount*sizeof(int));
1159       if (gpnAfterPositions == NULL) FailAllocMessage();
1160       memset(gpnAfterPositions, 0, gnAfterPositionsCount*sizeof(int));
1161    }
1162    index = 0;
1163    while ((line=UtilGetALine(FP)) != NULL) {
1164       int pos=(-1);
1165 
1166       scanLineNum++;
1167       if (*line == ']') {
1168          free(line);
1169          break;
1170       }
1171       if (index >= gnAfterPositionsCount) {
1172          fprintf(stderr, "Warning: too many lines in before_image.\n");
1173          free(line);
1174          break;
1175       }
1176       InitScan(line, "\t\n, ");
1177       if (GETINT("after_positions", pos, "after_positions_pos") == INVALID) {
1178          ok = FALSE;
1179          free(line);
1180          break;
1181       }
1182       gpnAfterPositions[index++] = pos;
1183       free(line);
1184    }
1185    if (ok && index < gnAfterPositionsCount) {
1186       fprintf(stderr, "Warning: too few lines in after_positions.\n");
1187       ok = FALSE;
1188    }
1189    if (!ok) {
1190       CleanUpBeforeImage();
1191    }
1192    return ok;
1193 }
1194 
ReadAfterImage(FP,Inbuf)1195 int ReadAfterImage(FP, Inbuf)
1196    FILE *FP;
1197    char *Inbuf;
1198 {
1199    struct ObjRec *obj_ptr=NULL;
1200    char *c_ptr;
1201    int ok=TRUE, count_expected=(-1), count=0;
1202 
1203    c_ptr = FindChar((int)'(', Inbuf);
1204    InitScan(c_ptr, "\t\n, ");
1205    if (GETINT("after_image", count_expected, "after_image_count") == INVALID) {
1206       return FALSE;
1207    }
1208    count = 0;
1209    while (ReadObj(FP, &obj_ptr)) {
1210       if (obj_ptr == NULL) {
1211          ok = FALSE;
1212          break;
1213       }
1214       obj_ptr->next = NULL;
1215       obj_ptr->prev = botObj;
1216       if (botObj == NULL) {
1217          topObj = obj_ptr;
1218       } else {
1219          botObj->next = obj_ptr;
1220       }
1221       botObj = obj_ptr;
1222       obj_ptr = NULL;
1223       count++;
1224    }
1225    if (ok && count != count_expected) {
1226       fprintf(stderr, "Warning: object count mismatched in after_image.\n");
1227       ok = FALSE;
1228    }
1229    return ok;
1230 }
1231 
1232 static
SelectObjects(top_obj,bot_obj)1233 void SelectObjects(top_obj, bot_obj)
1234    struct ObjRec *top_obj, *bot_obj;
1235 {
1236    struct ObjRec *obj_ptr;
1237 
1238    for (obj_ptr=bot_obj; obj_ptr != NULL; obj_ptr=obj_ptr->prev) {
1239       obj_ptr->tmp_parent = NULL;
1240       AddObjIntoSel(obj_ptr, NULL, topSel, &topSel, &botSel);
1241    }
1242    UpdSelBBox();
1243 }
1244 
1245 static
DeserializeCmd(psz_content_type,psz_buf,buf_sz,ppsz_plain_buf,pn_plain_buf_sz)1246 struct CmdRec *DeserializeCmd(psz_content_type, psz_buf, buf_sz, ppsz_plain_buf,
1247       pn_plain_buf_sz)
1248    char *psz_content_type, *psz_buf, **ppsz_plain_buf;
1249    int buf_sz, *pn_plain_buf_sz;
1250 {
1251    struct StkRec *stk_ptr=NULL;
1252    struct ObjRec *obj_ptr=NULL, *saved_top_obj=NULL, *saved_bot_obj=NULL;
1253    int read_status=TRUE, ok=TRUE, do_inflate=FALSE, need_to_free_buf=FALSE;
1254    struct CmdRec *cmd_ptr=NULL;
1255 
1256    if (gstWBInfo.listen_fp == NULL) {
1257       sprintf(gszMsgBox, "Cannot open '%s'.\n\n%s pid=%ld.",
1258             gstWBInfo.listen_fname, "Deserialization aborted for",
1259             gstWBInfo.pid);
1260       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1261       return NULL;
1262    }
1263 #ifdef _TGIF_DBG_WB2
1264    fprintf(stderr, "Content-Type: %s\n",
1265          (psz_content_type!=NULL) ? psz_content_type : "(unknown)");
1266    fprintf(stderr, "Content-Length: %1d\n", buf_sz);
1267 #endif /* _TGIF_DBG_WB2 */
1268    if (psz_content_type != NULL &&
1269          strcmp(psz_content_type, "application/x-tgif-cmd-z") == 0) {
1270       if (!HasZlibSupport()) {
1271          sprintf(gszMsgBox, "%s %s.\n\nDeserialization aborted.",
1272                TOOL_NAME, "is not compiled with ZLIB and cannot inflate()");
1273          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1274          return NULL;
1275       } else {
1276          if (gstWBInfo.gz_listen_fp == NULL) {
1277             sprintf(gszMsgBox, "Cannot open '%s'.\n\n%s pid=%ld.",
1278                   gstWBInfo.gz_listen_fname, "Deserialization aborted for",
1279                   gstWBInfo.pid);
1280             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1281             return NULL;
1282          }
1283          do_inflate = TRUE;
1284       }
1285    }
1286 
1287    if (do_inflate && HasZlibSupport()) {
1288       int rc=0;
1289 
1290       if (!DoInflate(psz_buf, buf_sz, gstWBInfo.gz_listen_fp, TRUE, &rc)) {
1291          ZlibError(rc, FALSE);
1292          return NULL;
1293       }
1294       buf_sz = (int)ftell(gstWBInfo.gz_listen_fp);
1295       psz_buf = (char*)malloc(buf_sz+1);
1296       if (psz_buf == NULL) FailAllocMessage();
1297       rewind(gstWBInfo.gz_listen_fp);
1298       if (fread(psz_buf, sizeof(char), buf_sz, gstWBInfo.gz_listen_fp) !=
1299             buf_sz) {
1300          sprintf(gszMsgBox, "Cannot read %1d bytes from '%s'.\n\n%s.",
1301                buf_sz, gstWBInfo.gz_listen_fname, "Deserialization aborted");
1302          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1303          UtilFree(psz_buf);
1304          return NULL;
1305       }
1306       psz_buf[buf_sz] = '\0';
1307       if (ppsz_plain_buf != NULL) {
1308          *pn_plain_buf_sz = buf_sz;
1309          *ppsz_plain_buf = UtilStrDup(psz_buf);
1310          if (*ppsz_plain_buf == NULL) FailAllocMessage();
1311       }
1312       need_to_free_buf = TRUE;
1313    }
1314 
1315 #ifdef _TGIF_DBG_WB2
1316    if (wb2DebugLevel == 0) {
1317       fprintf(stderr, "Received %1d bytes, pid = %ld, timestamp = (below)\n",
1318             buf_sz, gstWBInfo.pid);
1319    } else {
1320       fprintf(stderr, "<<<------------------------\n");
1321       fprintf(stderr, "%s\n", psz_buf);
1322       fprintf(stderr, "<<<------------------------\n");
1323       fprintf(stderr, "Received %1d bytes, pid = %ld, timestamp = (below)\n",
1324             buf_sz, gstWBInfo.pid);
1325    }
1326    PrintFullIDsOfObjects("In the beginning of DeserializeCmd()");
1327 #endif /* _TGIF_DBG_WB2 */
1328 
1329    rewind(gstWBInfo.listen_fp);
1330    writeFileFailed = FALSE;
1331    if (fprintf(gstWBInfo.listen_fp, "%s", psz_buf) == EOF) {
1332       writeFileFailed = TRUE;
1333    }
1334    if (writeFileFailed) {
1335       FailToWriteFileMessage(gstWBInfo.listen_fname);
1336       return NULL;
1337    }
1338    stk_ptr = SaveFileInfo();
1339    ResetFileInfo();
1340    /* if (usePaperSizeStoredInFile) ResetOnePageSize(); */
1341 
1342    ResetDeserializeCmd();
1343 
1344    rewind(gstWBInfo.listen_fp);
1345    importingFile = TRUE;
1346 
1347    strcpy(scanFileName, gstWBInfo.listen_fname);
1348    scanLineNum = 0;
1349    readingPageNum = loadedCurPageNum = 0;
1350    foundGoodStateObject = FALSE;
1351    while ((read_status=ReadObj(gstWBInfo.listen_fp, &obj_ptr)) == TRUE) {
1352       if (obj_ptr != NULL) {
1353          obj_ptr->tmp_parent = NULL;
1354          AdjForOldVersion(obj_ptr);
1355          AddObj(NULL, topObj, obj_ptr);
1356       }
1357    }
1358    importingFile = FALSE;
1359 
1360    if (read_status == INVALID) {
1361       sprintf(gszMsgBox, "File version too large (=%1d).  %s!",
1362             fileVersion, "Deserialization aborted");
1363       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1364       ok = FALSE;
1365    } else {
1366 #ifdef _TGIF_DBG_WB2
1367       fprintf(stderr, "%s, pid = %ld, timestamp = %1d/%s\n",
1368             "Command successfully parsed", gstWBInfo.pid, recordCmdLogicalClock,
1369             recordCmdSenderProcID);
1370 #endif /* _TGIF_DBG_WB2 */
1371       if (recordCmdLogicalClock+1 > gstWBInfo.logical_clock) {
1372          /* Lamport's Algorithm set logical_clock */
1373          gstWBInfo.logical_clock = recordCmdLogicalClock+1;
1374 #ifdef _TGIF_DBG_WB2
1375          fprintf(stderr, "Logical clock for pid = %ld set to %1d.\n",
1376                gstWBInfo.pid, gstWBInfo.logical_clock);
1377 #endif /* _TGIF_DBG_WB2 */
1378       }
1379    }
1380    if (!ok) {
1381       DelAllObj();
1382    } else {
1383       saved_top_obj = topObj;
1384       saved_bot_obj = botObj;
1385       topObj = botObj = NULL;
1386    }
1387    RestoreFileInfo(stk_ptr);
1388    ResetOnePageSize();
1389    free(stk_ptr);
1390    /*
1391     * This is new.  Does it work?!
1392     */
1393    UpdPageStyle(pageStyle);
1394 
1395    if (ok) {
1396       cmd_ptr = (struct CmdRec *)malloc(sizeof(struct CmdRec));
1397       if (cmd_ptr == NULL) FailAllocMessage();
1398       memset(cmd_ptr, 0, sizeof(struct CmdRec));
1399       cmd_ptr->serialized = TRUE; /* created from deserialization */
1400       cmd_ptr->top_before = cmd_ptr->bot_before = NULL;
1401       cmd_ptr->pos_before = (int*)gppszBeforeImage;
1402       cmd_ptr->count_before = gnBeforeImageCount;
1403       cmd_ptr->type = gstDeserializeCmd.type;
1404       cmd_ptr->undone = TRUE;
1405       cmd_ptr->include_tgif_obj = recordCmdIncludeTgifObj;
1406       cmd_ptr->new_colormap = recordCmdUsesNewColormap;
1407       cmd_ptr->logical_clock = recordCmdLogicalClock;
1408       if (*recordCmdSenderProcID != '\0') {
1409          cmd_ptr->sender_process_id = UtilStrDup(recordCmdSenderProcID);
1410          if (cmd_ptr->sender_process_id == NULL) FailAllocMessage();
1411       }
1412       cmd_ptr->first_redo_after_deserialize = TRUE;
1413       cmd_ptr->skipped = FALSE;
1414 #ifdef _TGIF_DBG_WB2
1415       DebugDumpCmd("<<< In DeserializeCmd()", cmd_ptr->type,
1416             cmd_ptr->logical_clock, cmd_ptr->sender_process_id);
1417 #endif /* _TGIF_DBG_WB2 */
1418       if (saved_top_obj != NULL) {
1419          SelectObjects(saved_top_obj, saved_bot_obj);
1420          CopySel(topSel, numObjSelected,
1421                &(cmd_ptr->top_after), &(cmd_ptr->bot_after));
1422          cmd_ptr->pos_after = gpnAfterPositions;
1423          cmd_ptr->count_after = gnAfterPositionsCount;
1424          RemoveAllSel();
1425       } else {
1426          cmd_ptr->top_after = cmd_ptr->bot_after = NULL;
1427          cmd_ptr->pos_after = NULL;
1428          cmd_ptr->count_after = 0;
1429       }
1430       gppszBeforeImage = NULL;
1431       gnBeforeImageCount = 0;
1432       gpnAfterPositions = NULL;
1433       gnAfterPositionsCount = 0;
1434    }
1435    /*
1436     * Move this to the end of ProcessRemoteCmd() because we may need
1437     *         some information from gpDeserializeSubCmd.
1438     *
1439     * DeserializationCleanUp();
1440     */
1441 
1442 #ifdef _TGIF_DBG_WB2
1443    PrintFullIDsOfObjects("At the end of DeserializeCmd()");
1444 #endif /* _TGIF_DBG_WB2 */
1445 
1446    if (need_to_free_buf) UtilFree(psz_buf);
1447 
1448    return cmd_ptr;
1449 }
1450 
1451 static
TotalOrderForTwo(older_cmd,newer_cmd)1452 int TotalOrderForTwo(older_cmd, newer_cmd)
1453    struct CmdRec *older_cmd, *newer_cmd;
1454    /*
1455     * Note: If logical clocks and host names are the same, and if pid in
1456     *       older_cmd is less than pid in newer_cmd, will return TRUE!
1457     */
1458 {
1459    int comparison=0;
1460 
1461    if (older_cmd == NULL || newer_cmd == NULL) return TRUE;
1462 
1463    if (older_cmd->logical_clock > newer_cmd->logical_clock) {
1464       return FALSE;
1465    } else if (older_cmd->logical_clock < newer_cmd->logical_clock) {
1466       return TRUE;
1467    }
1468    comparison = strcmp(older_cmd->sender_process_id,
1469          newer_cmd->sender_process_id);
1470    TgAssert(comparison != 0,
1471          "Identical logical clock detected in TotalOrderForTwo()", NULL);
1472    return (comparison < 0);
1473 }
1474 
1475 #ifdef _TGIF_DBG_WB2
1476 static
DumpCmdStack(prefix_string)1477 void DumpCmdStack(prefix_string)
1478    char *prefix_string;
1479    /* Dump the command stack, last one first */
1480 {
1481    struct CmdRec *cmd_ptr=NULL;
1482 
1483    if (prefix_string != NULL) fprintf(stderr, "%s\n", prefix_string);
1484    for (cmd_ptr=gstWBInfo.last_cmd; cmd_ptr != NULL; cmd_ptr=cmd_ptr->prev) {
1485       char buf[256];
1486 
1487       if (cmd_ptr->skipped) {
1488          sprintf(buf, "\tcmd_ptr->next = 0x%08lx, (SKIPPED)",
1489                (long)cmd_ptr->next);
1490       } else {
1491          sprintf(buf, "\tcmd_ptr->next = 0x%08lx", (long)cmd_ptr->next);
1492       }
1493       DebugDumpCmd(buf, cmd_ptr->type, cmd_ptr->logical_clock,
1494             cmd_ptr->sender_process_id);
1495    }
1496 }
1497 #endif /* _TGIF_DBG_WB2 */
1498 
FindCmdInsertionPoint(cmd_to_insert,pp_immed_right_cmd)1499 void FindCmdInsertionPoint(cmd_to_insert, pp_immed_right_cmd)
1500    struct CmdRec *cmd_to_insert, **pp_immed_right_cmd;
1501    /*
1502     * On return, cmd_to_insert is to be inserted immediately to the left
1503     *       of *pp_immed_right_cmd.
1504     */
1505 {
1506    struct CmdRec *cmd_ptr=NULL;
1507 
1508    for (cmd_ptr=gstWBInfo.last_cmd; cmd_ptr != NULL; cmd_ptr=cmd_ptr->prev) {
1509       if (TotalOrderForTwo(cmd_ptr, cmd_to_insert)) {
1510          *pp_immed_right_cmd = cmd_ptr->next;
1511          return;
1512       }
1513    }
1514    *pp_immed_right_cmd = gstWBInfo.first_cmd;
1515 }
1516 
FindShadowCmdInsertionPoint(cmd_to_insert,pp_immed_right_cmd)1517 void FindShadowCmdInsertionPoint(cmd_to_insert, pp_immed_right_cmd)
1518    struct CmdRec *cmd_to_insert, **pp_immed_right_cmd;
1519    /*
1520     * On return, cmd_to_insert is to be inserted immediately to the left
1521     *       of *pp_immed_right_cmd.
1522     */
1523 {
1524    struct CmdRec *cmd_ptr=NULL;
1525 
1526    for (cmd_ptr=gstWBInfo.last_shadow_cmd; cmd_ptr != NULL;
1527          cmd_ptr=cmd_ptr->prev) {
1528       if (TotalOrderForTwo(cmd_ptr, cmd_to_insert)) {
1529          *pp_immed_right_cmd = cmd_ptr->next;
1530          return;
1531       }
1532    }
1533    *pp_immed_right_cmd = gstWBInfo.first_shadow_cmd;
1534 }
1535 
1536 static
HighLightExistingObjects()1537 void HighLightExistingObjects()
1538    /*
1539     * If select object no longer exists, don't select and highlight it!
1540     */
1541 {
1542    int something_deleted=FALSE;
1543    struct SelRec *sel_ptr=NULL, *next_sel=NULL;
1544 
1545    for (sel_ptr=topSel; sel_ptr != NULL; sel_ptr=next_sel) {
1546       next_sel = sel_ptr->next;
1547       if (!IsTopLevelObject(sel_ptr->obj)) {
1548          UnlinkSel(sel_ptr, &topSel, &botSel);
1549          free(sel_ptr);
1550          something_deleted = TRUE;
1551       }
1552    }
1553    if (something_deleted) UpdSelBBox();
1554    HighLightForward();
1555 }
1556 
CleanUpObsoletedWBCmds(stopped_cmd_ptr)1557 void CleanUpObsoletedWBCmds(stopped_cmd_ptr)
1558    struct CmdRec *stopped_cmd_ptr;
1559 {
1560    struct CmdRec *cmd_ptr=NULL;
1561    int num_records=0;
1562 
1563    for (cmd_ptr=stopped_cmd_ptr->prev; cmd_ptr != NULL; cmd_ptr=cmd_ptr->prev) {
1564       num_records++;
1565    }
1566    if (num_records > 0) {
1567       struct CmdRec *prev_cmd=NULL;
1568       double inc=(100.0/((double)num_records)), percent_start=0.0;
1569 
1570       ShowInterrupt(1);
1571       SaveStatusStrings();
1572       for (cmd_ptr=stopped_cmd_ptr->prev; cmd_ptr != NULL; cmd_ptr=prev_cmd,
1573             percent_start+=inc) {
1574          prev_cmd = cmd_ptr->prev;
1575          DeleteARedoRecord(cmd_ptr, percent_start,
1576                min(((double)percent_start+inc),((double)100.0)));
1577       }
1578       RestoreStatusStrings();
1579       HideInterrupt();
1580    }
1581    gstWBInfo.first_cmd = stopped_cmd_ptr;
1582    gstWBInfo.first_cmd->prev = NULL;
1583 
1584    CleanUpWBShadowCmds();
1585 }
1586 
1587 static
HandleChatLine(cmd_ptr)1588 void HandleChatLine(cmd_ptr)
1589    struct CmdRec *cmd_ptr;
1590 {
1591    struct ChatSubCmdRec *pChatSubCmdInfo=(&gpDeserializeSubCmd->detail.chat);
1592 
1593    switch (pChatSubCmdInfo->type) {
1594    case CHAT_STATE_NORMAL:
1595       ChatAppendChatLine(&pChatSubCmdInfo->tfi, pChatSubCmdInfo->nick_name,
1596             pChatSubCmdInfo->encoding, pChatSubCmdInfo->buf);
1597       break;
1598    case CHAT_STATE_HELLO:
1599       break;
1600    case CHAT_STATE_DISCONNECT:
1601       /* handle explicit user disconnect */
1602       break;
1603    }
1604    /*
1605     * Handle the chat line...
1606     */
1607    DeleteARedoRecord(cmd_ptr, 0, 0);
1608    gstWBInfo.cur_cmd = NULL;
1609 }
1610 
ProcessRemoteCmd(psz_content_type,psz_buf,buf_sz)1611 void ProcessRemoteCmd(psz_content_type, psz_buf, buf_sz)
1612    char *psz_content_type, *psz_buf;
1613    int buf_sz;
1614 {
1615    struct SelRec *saved_top_sel=topSel, *saved_bot_sel=botSel;
1616    struct CmdRec *cmd_ptr=NULL;
1617    char *psz_plain_buf=NULL;
1618    int highlighted_before=FALSE, plain_buf_sz=0;
1619 
1620    if (topSel != NULL) {
1621       highlighted_before = TRUE;
1622       HighLightReverse();
1623       topSel = botSel = NULL;
1624    }
1625    gstWBInfo.cur_cmd = DeserializeCmd(psz_content_type, psz_buf, buf_sz,
1626          &psz_plain_buf, &plain_buf_sz);
1627 
1628    if (gstWBInfo.cur_cmd != NULL) {
1629       struct CmdRec *immed_right_cmd=NULL;
1630       int cur_cmd_is_wb_clearall=(gstWBInfo.cur_cmd->type == CMD_WB_CLEARALL);
1631 
1632       if (gstWBInfo.cur_cmd->type == CMD_CHAT_A_LINE) {
1633          HandleChatLine(gstWBInfo.cur_cmd);
1634          /*
1635           * May be we need to allocate subcmd pointer here.
1636           */
1637       } else {
1638          if (gstWBInfo.cur_cmd->type == CMD_MOVE) {
1639             gstWBInfo.cur_cmd->subcmd =
1640                   (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
1641             if (gstWBInfo.cur_cmd->subcmd == NULL) FailAllocMessage();
1642             memset(gstWBInfo.cur_cmd->subcmd, 0, sizeof(struct SubCmdRec));
1643             gstWBInfo.cur_cmd->subcmd->detail.move.dx =
1644                   gpDeserializeSubCmd->detail.move.dx;
1645             gstWBInfo.cur_cmd->subcmd->detail.move.dy =
1646                   gpDeserializeSubCmd->detail.move.dy;
1647          } else if (gstWBInfo.cur_cmd->type == CMD_WB_SLIDESHOW) {
1648             gstWBInfo.cur_cmd->subcmd =
1649                   (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
1650             if (gstWBInfo.cur_cmd->subcmd == NULL) FailAllocMessage();
1651             memset(gstWBInfo.cur_cmd->subcmd, 0, sizeof(struct SubCmdRec));
1652             gstWBInfo.cur_cmd->subcmd->detail.slideshow.into_slideshow =
1653                   gpDeserializeSubCmd->detail.slideshow.into_slideshow;
1654          }
1655 #ifdef _TGIF_DBG_WB2
1656          DumpCmdStack("Before FindCmdInsertionPoint()");
1657 #endif /* _TGIF_DBG_WB2 */
1658          /*
1659           * FindShadowCmdInsertionPoint() examine the logical clock of the new
1660           *       command and decides where to insert it in the shadow cmd list.
1661           */
1662          FindShadowCmdInsertionPoint(gstWBInfo.cur_cmd, &immed_right_cmd);
1663 
1664          if (immed_right_cmd == NULL) {
1665             /* append */
1666             CopyAndInsertCmd(TRUE,
1667                   (psz_plain_buf==NULL ? psz_buf : psz_plain_buf),
1668                   gstWBInfo.last_shadow_cmd, NULL, gstWBInfo.cur_cmd,
1669                   &gstWBInfo.first_shadow_cmd, &gstWBInfo.last_shadow_cmd);
1670          } else {
1671             /* insert */
1672             CopyAndInsertCmd(TRUE,
1673                   (psz_plain_buf==NULL ? psz_buf : psz_plain_buf),
1674                   immed_right_cmd->prev, immed_right_cmd, gstWBInfo.cur_cmd,
1675                   &gstWBInfo.first_shadow_cmd, &gstWBInfo.last_shadow_cmd);
1676          }
1677          immed_right_cmd = NULL;
1678          /*
1679           * FindCmdInsertionPoint() examine the logical clock of the new command
1680           *       and decides where to insert it.
1681           */
1682          FindCmdInsertionPoint(gstWBInfo.cur_cmd, &immed_right_cmd);
1683 
1684          if (immed_right_cmd == NULL) {
1685             /* append */
1686             InsertCmd(gstWBInfo.last_cmd, NULL, gstWBInfo.cur_cmd,
1687                   &gstWBInfo.first_cmd, &gstWBInfo.last_cmd);
1688          } else {
1689             /* insert */
1690             InsertCmd(immed_right_cmd->prev, immed_right_cmd, gstWBInfo.cur_cmd,
1691                   &gstWBInfo.first_cmd, &gstWBInfo.last_cmd);
1692          }
1693 #ifdef _TGIF_DBG_WB2
1694          DumpCmdStack("After FindCmdInsertionPoint()");
1695 #endif /* _TGIF_DBG_WB2 */
1696          if (immed_right_cmd != NULL) {
1697             /*
1698              * Undo all the commands to the right of gstWBInfo.cur_cmd.
1699              * Do not perform the undo if the command is skipped.
1700              */
1701             for (cmd_ptr=gstWBInfo.last_cmd; cmd_ptr != gstWBInfo.cur_cmd &&
1702                   cmd_ptr->type != CMD_WB_CLEARALL; cmd_ptr=cmd_ptr->prev) {
1703                if (cmd_ptr->skipped) {
1704 #ifdef _TGIF_DBG_WB2
1705                   strcpy(gszMsgBox, "*** No need to UndoACmd()");
1706                   DebugDumpCmd(gszMsgBox, cmd_ptr->type, cmd_ptr->logical_clock,
1707                         cmd_ptr->sender_process_id);
1708 #endif /* _TGIF_DBG_WB2 */
1709                   cmd_ptr->skipped = FALSE;
1710                } else {
1711 #ifdef _TGIF_DBG_WB2
1712                   strcpy(gszMsgBox, "*** Just before UndoACmd()");
1713                   DebugDumpCmd(gszMsgBox, cmd_ptr->type, cmd_ptr->logical_clock,
1714                         cmd_ptr->sender_process_id);
1715                   PrintFullIDsOfObjects("\t");
1716 #endif /* _TGIF_DBG_WB2 */
1717                   UndoACmd(cmd_ptr, FALSE, TRUE);
1718 #ifdef _TGIF_DBG_WB2
1719                   DebugDumpCmd("*** After UndoACmd()",
1720                         cmd_ptr->type, cmd_ptr->logical_clock,
1721                         cmd_ptr->sender_process_id);
1722                   PrintFullIDsOfObjects("\t");
1723 #endif /* _TGIF_DBG_WB2 */
1724                   if (topSel != NULL) RemoveAllSel();
1725                }
1726             }
1727             if (cmd_ptr != gstWBInfo.cur_cmd) {
1728                gstWBInfo.cur_cmd = cmd_ptr;
1729             }
1730          }
1731          /*
1732           * Redo all the commands starting from gstWBInfo.cur_cmd.
1733           */
1734          if (gstWBInfo.cur_cmd->type == CMD_WB_CLEARALL) {
1735             CleanUpObsoletedWBCmds(gstWBInfo.cur_cmd);
1736             if (cur_cmd_is_wb_clearall) {
1737                struct ClearAllSubCmdRec *clearall=
1738                      &gpDeserializeSubCmd->detail.clearall;
1739 
1740                CleanUpDrawingWindow();
1741                ClearFileInfo(TRUE);
1742                SetFileModified(FALSE);
1743                ClearAndRedrawDrawWindow();
1744                CheckFileAttrsInLoad();
1745                Msg("WhiteBoard cleared by peer.");
1746                DelAllPages();
1747                lastPageNum = 1;
1748                InitPage();
1749                ShowPage();
1750                if (!(pageStyle == clearall->page_style &&
1751                      fabs(printMag-clearall->print_mag) < INT_TOL)) {
1752                   pageStyle = clearall->page_style;
1753                   printMag = clearall->print_mag;
1754                   UpdPageStyle(pageStyle);
1755 
1756                   UpdDrawWinWH();
1757                   RedrawScrollBars();
1758                   UpdDrawWinBBox();
1759 
1760                   SetDefaultDrawWinClipRecs();
1761 
1762                   DrawPaperBoundary(drawWindow);
1763                   RedrawGridLines(drawWindow);
1764                   RedrawPageLines(drawWindow);
1765                   RedrawRulers();
1766                   RedrawChoiceWindow();
1767 
1768                   RedrawTitleWindow();
1769                }
1770             }
1771          }
1772          for (cmd_ptr=gstWBInfo.cur_cmd; cmd_ptr != NULL;
1773                cmd_ptr=cmd_ptr->next) {
1774 #ifdef _TGIF_DBG_WB2
1775             DebugDumpCmd("--- Just before RedoACmd()",
1776                   cmd_ptr->type, cmd_ptr->logical_clock,
1777                   cmd_ptr->sender_process_id);
1778             PrintFullIDsOfObjects("\t");
1779 #endif /* _TGIF_DBG_WB2 */
1780             if (!RedoACmd(cmd_ptr, FALSE, TRUE)) {
1781                cmd_ptr->skipped = TRUE;
1782 #ifdef _TGIF_DBG_WB2
1783                DebugDumpCmd("=== Skip RedoACmd()",
1784                      cmd_ptr->type, cmd_ptr->logical_clock,
1785                      cmd_ptr->sender_process_id);
1786                PrintFullIDsOfObjects("\t");
1787 #endif /* _TGIF_DBG_WB2 */
1788             } else {
1789 #ifdef NOT_DEFINED
1790                /* insanity check! */
1791                fprintf(stderr, "Sanity check: %s\n",
1792                      "need to comment this before distributing the code!");
1793                if (topSel != NULL) RemoveAllSel();
1794                UndoACmd(cmd_ptr, FALSE, TRUE);
1795                if (topSel != NULL) RemoveAllSel();
1796                if (!RedoACmd(cmd_ptr, FALSE, TRUE)) {
1797                   fprintf(stderr, "\7\7\7Oh no!!!  RedoACmd() failed!\n");
1798                }
1799 #endif /* NOT_DEFINED */
1800 #ifdef _TGIF_DBG_WB2
1801                DebugDumpCmd("--- Just after RedoACmd()",
1802                      cmd_ptr->type, cmd_ptr->logical_clock,
1803                      cmd_ptr->sender_process_id);
1804                PrintFullIDsOfObjects("\t");
1805 #endif /* _TGIF_DBG_WB2 */
1806                if (topSel != NULL) RemoveAllSel();
1807             }
1808          }
1809 #ifdef _TGIF_DBG_WB2
1810          PrintFullIDsOfObjects("At end of ProcessRemoteCmd()");
1811          fprintf(stderr, "%s%s\n",
1812                "========================================",
1813                "========================================");
1814 #endif /* _TGIF_DBG_WB2 */
1815       }
1816    }
1817    DeserializationCleanUp();
1818    ResetDeserializeCmd();
1819 
1820    topSel = saved_top_sel;
1821    botSel = saved_bot_sel;
1822    UpdSelBBox();
1823    if (highlighted_before) {
1824       HighLightExistingObjects();
1825    }
1826    UtilFree(psz_plain_buf);
1827 }
1828 
1829 /* =================== Pack and Unpack current state Functions ======= */
1830 
1831 static
PackCurrentTGWBState(p_cur_state)1832 void PackCurrentTGWBState(p_cur_state)
1833     CurStatus *p_cur_state;
1834 {
1835    char tmp_fname[MAXPATHLENGTH], *buf=NULL, header[MAXSTRING<<1];
1836    char gz_tmp_fname[MAXPATHLENGTH];
1837    int content_sz=0, ok=TRUE, header_sz=0, num_cmds=0, cur_cmd_pos=0;
1838    int do_deflate=TRUE;
1839    struct CmdRec *cmd_ptr=NULL;
1840    long loc_sec=0L, loc_msec=0L;
1841    FILE *fp=NULL, *gz_fp=NULL;
1842 
1843    if (HasZlibSupport()) {
1844 #ifdef _TGIF_DBG_WB2
1845       do_deflate = FALSE;
1846 #endif /* _TGIF_DBG_WB2 */
1847    } else {
1848       do_deflate = FALSE;
1849    }
1850    memset(p_cur_state, 0, sizeof(CurStatus));
1851    if (MkTempFile(tmp_fname, sizeof(tmp_fname), tmpDir, TOOL_NAME) == NULL) {
1852       fprintf(stderr, TgLoadString(STID_CANT_CREATE_NAMED_TMP_FILE), tmp_fname);
1853       fprintf(stderr, "\n");
1854       return;
1855    }
1856    snprintf(gz_tmp_fname, sizeof(gz_tmp_fname), "%s.z", tmp_fname);
1857 
1858    if ((fp=fopen(tmp_fname, "w+")) == NULL) {
1859       FailToOpenMessage(tmp_fname, "w", NULL);
1860       return;
1861    }
1862    if ((gz_fp=fopen(gz_tmp_fname, "w+")) == NULL) {
1863       FailToOpenMessage(gz_tmp_fname, "w", NULL);
1864       fclose(fp);
1865       unlink(tmp_fname);
1866       return;
1867    }
1868    writeFileFailed = FALSE;
1869 
1870    UtilGetMilliSecTime(&loc_sec, &loc_msec);
1871    if (fprintf(fp, "%%TGWB begin packing - %ld.%ld\n", loc_sec, loc_msec) ==
1872          EOF) {
1873       writeFileFailed = TRUE;
1874    }
1875    for (cmd_ptr=gstWBInfo.first_shadow_cmd; cmd_ptr != NULL;
1876          cmd_ptr=cmd_ptr->next) {
1877       SerializationInfo si;
1878 
1879       memset(&si, 0, sizeof(SerializationInfo));
1880       PrepareExtendedSerializationInfo(cmd_ptr, &si);
1881       if (SaveExtendedCmd(fp, cmd_ptr, &si)) {
1882          if (cmd_ptr == gstWBInfo.cur_cmd) {
1883             cur_cmd_pos = num_cmds;
1884          }
1885          num_cmds++;
1886       }
1887    }
1888    ok = SaveExtendedCmdInfo(fp, num_cmds, cur_cmd_pos);
1889 
1890    if (fprintf(fp, "%%TGWB end - %ld.%ld\n", loc_sec, loc_msec) == EOF) {
1891       writeFileFailed = TRUE;
1892    }
1893    if (writeFileFailed) {
1894       FailToWriteFileMessage(tmp_fname);
1895       fclose(fp);
1896       unlink(tmp_fname);
1897       fclose(gz_fp);
1898       unlink(gz_tmp_fname);
1899       return;
1900    }
1901    if (!ok) {
1902       fclose(fp);
1903       unlink(tmp_fname);
1904       fclose(gz_fp);
1905       unlink(gz_tmp_fname);
1906       return;
1907    }
1908    fflush(fp);
1909    content_sz = (int)ftell(fp);
1910    /*
1911     * From: <PID>:<IP>\r\n
1912     * Content-Type: application/x-tgif-cmd\r\n
1913     * Content-Length: <LENGTH>\r\n
1914     * \r\n
1915     * <DATA of size LENGTH>
1916     */
1917    if (do_deflate && HasZlibSupport()) {
1918       int rc=0;
1919 
1920       if (!DoDeflate(fp, NULL, content_sz, gz_fp, TRUE, TRUE, &rc)) {
1921          ZlibError(rc, TRUE);
1922          do_deflate = FALSE;
1923       } else {
1924          content_sz = (int)ftell(gz_fp);
1925       }
1926    }
1927    if (do_deflate) {
1928       sprintf(header, "%s%s\r\n%s%s\r\n%s%1d\r\n\r\n",
1929             "From: ", gszLocalPID,
1930             "Content-Type: ", "application/x-tgif-cmd-z",
1931             "Content-Length: ", content_sz);
1932       header_sz = strlen(header);
1933       buf = (char*)malloc((header_sz+content_sz+1)*sizeof(char));
1934       if (buf == NULL) FailAllocMessage();
1935       strcpy(buf, header);
1936       rewind(gz_fp);
1937       if (fread(&buf[header_sz], sizeof(char), content_sz, gz_fp) !=
1938             content_sz) {
1939          sprintf(gszMsgBox,
1940                "Error in reading '%s'.\n\nPackCurrentTGWBState() aborted.",
1941                gz_tmp_fname);
1942          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1943 
1944          UtilFree(buf);
1945          fclose(fp);
1946          unlink(tmp_fname);
1947          fclose(gz_fp);
1948          unlink(gz_tmp_fname);
1949          return;
1950       }
1951    } else {
1952       sprintf(header, "%s%s\r\n%s%s\r\n%s%1d\r\n\r\n",
1953             "From: ", gszLocalPID,
1954             "Content-Type: ", "application/x-tgif-cmd",
1955             "Content-Length: ", content_sz);
1956       header_sz = strlen(header);
1957       buf = (char*)malloc((header_sz+content_sz+1)*sizeof(char));
1958       if (buf == NULL) FailAllocMessage();
1959       strcpy(buf, header);
1960       rewind(fp);
1961       if (fread(&buf[header_sz], sizeof(char), content_sz, fp) !=
1962             content_sz) {
1963          sprintf(gszMsgBox,
1964                "Error in reading '%s'.\n\nPackCurrentTGWBState() aborted.",
1965                tmp_fname);
1966          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
1967 
1968          UtilFree(buf);
1969          fclose(fp);
1970          unlink(tmp_fname);
1971          fclose(gz_fp);
1972          unlink(gz_tmp_fname);
1973          return;
1974       }
1975    }
1976    buf[header_sz+content_sz] = '\0';
1977 #ifdef _TGIF_DBG_WB2
1978    if (wb2DebugLevel == 0) {
1979       fprintf(stderr, "Sending %1d bytes, pid = %ld!\n",
1980             header_sz+content_sz+2, gstWBInfo.pid);
1981    } else {
1982       fprintf(stderr, "---------------------------\n");
1983       if (do_deflate) {
1984          fprintf(stderr, "%s", header);
1985          fprintf(stderr, "[content not displayed] ...\n");
1986       } else {
1987          fprintf(stderr, "%s\n", buf);
1988       }
1989       fprintf(stderr, "---------------------------\n");
1990       fprintf(stderr, "Sent %1d bytes, pid = %ld!\n", header_sz+content_sz+2,
1991             gstWBInfo.pid);
1992    }
1993    DebugDumpCmd(">>> In PackCurrentTGWBState()",
1994          (-1), (-1), gszLocalPID);
1995    PrintFullIDsOfObjects("In PackCurrentTGWBState()");
1996 #endif /* _TGIF_DBG_WB2 */
1997    fclose(fp);
1998    unlink(tmp_fname);
1999    fclose(gz_fp);
2000    unlink(gz_tmp_fname);
2001 
2002    /* It is important to include the terminating '\0' */
2003    p_cur_state->data = buf;
2004    p_cur_state->size = header_sz+content_sz+1;
2005 }
2006 
2007 static
CheckUnpackState(read_status)2008 int CheckUnpackState(read_status)
2009    int read_status;
2010 {
2011    int ok=TRUE;
2012 
2013    if (read_status == INVALID) {
2014       sprintf(gszMsgBox, "File version too large (=%1d).  %s!",
2015             fileVersion, "UnpackCurrentTGWBState() aborted");
2016       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2017       ok = FALSE;
2018    } else {
2019 #ifdef _TGIF_DBG_WB2
2020       fprintf(stderr, "%s, pid = %ld, timestamp = %1d/%s\n",
2021             "Command successfully parsed", gstWBInfo.pid, recordCmdLogicalClock,
2022             recordCmdSenderProcID);
2023 #endif /* _TGIF_DBG_WB2 */
2024       if (recordCmdLogicalClock+1 > gstWBInfo.logical_clock) {
2025          /* Lamport's Algorithm set logical_clock */
2026          gstWBInfo.logical_clock = recordCmdLogicalClock+1;
2027 #ifdef _TGIF_DBG_WB2
2028          fprintf(stderr, "Logical clock for pid = %ld set to %1d.\n",
2029                gstWBInfo.pid, gstWBInfo.logical_clock);
2030 #endif /* _TGIF_DBG_WB2 */
2031       }
2032    }
2033    return ok;
2034 }
2035 
2036 static
CreateCmdFromSerializedData(saved_top_obj,saved_bot_obj)2037 struct CmdRec *CreateCmdFromSerializedData(saved_top_obj, saved_bot_obj)
2038    struct ObjRec *saved_top_obj, *saved_bot_obj;
2039 {
2040    struct CmdRec *cmd_ptr=(struct CmdRec *)malloc(sizeof(struct CmdRec));
2041 
2042    if (cmd_ptr == NULL) FailAllocMessage();
2043    memset(cmd_ptr, 0, sizeof(struct CmdRec));
2044    cmd_ptr->serialized = TRUE; /* created from deserialization */
2045    cmd_ptr->top_before = cmd_ptr->bot_before = NULL;
2046    cmd_ptr->pos_before = (int*)gppszBeforeImage;
2047    cmd_ptr->count_before = gnBeforeImageCount;
2048    cmd_ptr->type = gstDeserializeCmd.type;
2049    cmd_ptr->undone = TRUE;
2050    cmd_ptr->include_tgif_obj = recordCmdIncludeTgifObj;
2051    cmd_ptr->new_colormap = recordCmdUsesNewColormap;
2052    cmd_ptr->logical_clock = recordCmdLogicalClock;
2053    if (*recordCmdSenderProcID != '\0') {
2054       cmd_ptr->sender_process_id = UtilStrDup(recordCmdSenderProcID);
2055       if (cmd_ptr->sender_process_id == NULL) FailAllocMessage();
2056    } else {
2057       fprintf(stderr,
2058             "Missing sender_process_id in CreateCmdFromSerializedData().\n");
2059    }
2060    cmd_ptr->first_redo_after_deserialize = TRUE;
2061    cmd_ptr->skipped = FALSE;
2062 #ifdef _TGIF_DBG_WB2
2063    DebugDumpCmd("<<< In CreateCmdFromSerializedData()", cmd_ptr->type,
2064          cmd_ptr->logical_clock, cmd_ptr->sender_process_id);
2065 #endif /* _TGIF_DBG_WB2 */
2066    if (saved_top_obj != NULL) {
2067       SelectObjects(saved_top_obj, saved_bot_obj);
2068       CopySel(topSel, numObjSelected,
2069             &(cmd_ptr->top_after), &(cmd_ptr->bot_after));
2070       cmd_ptr->pos_after = gpnAfterPositions;
2071       cmd_ptr->count_after = gnAfterPositionsCount;
2072       RemoveAllSel();
2073    } else {
2074       cmd_ptr->top_after = cmd_ptr->bot_after = NULL;
2075       cmd_ptr->pos_after = NULL;
2076       cmd_ptr->count_after = 0;
2077    }
2078    gppszBeforeImage = NULL;
2079    gnBeforeImageCount = 0;
2080    gpnAfterPositions = NULL;
2081    gnAfterPositionsCount = 0;
2082 
2083    return cmd_ptr;
2084 }
2085 
2086 static
GetContentInfoFromBuf(buf,content_type_buf,content_type_buf_sz,pn_content_length,ppsz_buf_data_start)2087 int GetContentInfoFromBuf(buf, content_type_buf, content_type_buf_sz,
2088       pn_content_length, ppsz_buf_data_start)
2089    char *buf, *content_type_buf, **ppsz_buf_data_start;
2090    int content_type_buf_sz, *pn_content_length;
2091 {
2092    char *psz_start=buf, *psz=NULL;
2093    char *content_type_prefix="Content-Type: ";
2094    char *content_len_prefix="Content-Length: ";
2095    int content_type_prefix_len=strlen(content_type_prefix);
2096    int content_len_prefix_len=strlen(content_len_prefix);
2097    int found_content_type=FALSE, found_content_len=FALSE;
2098 
2099    psz = strstr(psz_start, "\r\n");
2100    while (psz != NULL) {
2101       *psz = '\0';
2102       if (*psz_start == '\0') {
2103          *psz = '\r';
2104          psz_start = &psz[2];
2105          if (ppsz_buf_data_start != NULL) *ppsz_buf_data_start = psz_start;
2106          return (found_content_type && found_content_len);
2107       } else if (UtilStrNCaseCmp(psz_start, content_type_prefix,
2108             content_type_prefix_len) == 0) {
2109          UtilStrCpyN(content_type_buf, content_type_buf_sz,
2110                &psz_start[content_type_prefix_len]);
2111          UtilTrimBlanks(content_type_buf);
2112          found_content_type = TRUE;
2113       } else if (UtilStrNCaseCmp(psz_start, content_len_prefix,
2114             content_len_prefix_len) == 0) {
2115          char buf2[80];
2116          int ival=0;
2117 
2118          UtilStrCpyN(buf2, sizeof(buf2),
2119                &psz_start[content_len_prefix_len]);
2120          UtilTrimBlanks(buf2);
2121          if (sscanf(buf2, "%d", &ival) == 1) {
2122             if (pn_content_length != NULL) *pn_content_length = ival;
2123             found_content_len = TRUE;
2124          }
2125       }
2126       *psz = '\r';
2127       psz_start = &psz[2];
2128       psz = strstr(psz_start, "\r\n");
2129    }
2130    return FALSE;
2131 }
2132 
2133 static
ReadPastWrapper(fp,pn_file_pos)2134 int ReadPastWrapper(fp, pn_file_pos)
2135    FILE *fp;
2136    int *pn_file_pos;
2137 {
2138    char *buf=NULL;
2139    char *psz_looking_for="%TGWB begin packing - ";
2140    int len=strlen(psz_looking_for);
2141 
2142    while ((buf=UtilGetALine(fp)) != NULL) {
2143       if (strncmp(buf, psz_looking_for, len) == 0) {
2144          if (pn_file_pos != NULL) *pn_file_pos = (int)ftell(fp);
2145          UtilFree(buf);
2146          return TRUE;
2147       }
2148       UtilFree(buf);
2149    }
2150    return FALSE;
2151 }
2152 
2153 static
ReadPastHeader(fp,pn_file_pos)2154 int ReadPastHeader(fp, pn_file_pos)
2155    FILE *fp;
2156    int *pn_file_pos;
2157    /*
2158     * The From, Content-Type, Content-Length header is optional.  So,
2159     *         need to handle the case where there is a header and the case
2160     *         where there is none.
2161     */
2162 {
2163    char *psz_looking_for="%TGWB begin - ";
2164    int len=strlen(psz_looking_for);
2165    int cur_pos=(int)ftell(fp);
2166    char *buf=NULL;
2167 
2168    while ((buf=UtilGetALine(fp)) != NULL) {
2169       char obj_name[80];
2170 
2171       *obj_name = '\0';
2172       UtilTrimBlanks(buf);
2173       if (*buf == '\0') {
2174          if (pn_file_pos != NULL) *pn_file_pos = (int)ftell(fp);
2175          UtilFree(buf);
2176          return TRUE;
2177       } else if (strncmp(buf, psz_looking_for, len) == 0) {
2178          if (pn_file_pos != NULL) *pn_file_pos = cur_pos;
2179          UtilFree(buf);
2180          return TRUE;
2181       } else if (*buf == ']' || *buf == '%') {
2182          fprintf(stderr,
2183                "Unexpected line (start with '%c' read in ReadPastHeader().\n",
2184                *buf);
2185          UtilFree(buf);
2186          return FALSE;
2187       } else if (ParseStr(buf, (int)'(', obj_name, sizeof(obj_name)) == NULL) {
2188          /* it's probably okay */
2189       } else if (strcmp(obj_name, "cmdxinfo") == 0) {
2190          int ok=ReadExtendedCmdInfo(fp, buf);
2191 
2192          UtilFree(buf);
2193          return ok;
2194       }
2195       UtilFree(buf);
2196       cur_pos = (int)ftell(fp);
2197    }
2198    return FALSE;
2199 }
2200 
2201 static
ReadAheadOverACmd(fp,pn_file_pos)2202 int ReadAheadOverACmd(fp, pn_file_pos)
2203    FILE *fp;
2204    int *pn_file_pos;
2205 {
2206    char *buf=NULL;
2207    char *psz_looking_for="%TGWB end - ";
2208    int len=strlen(psz_looking_for);
2209 
2210    while ((buf=UtilGetALine(fp)) != NULL) {
2211       if (strncmp(buf, psz_looking_for, len) == 0) {
2212          if (pn_file_pos != NULL) *pn_file_pos = (int)ftell(fp);
2213          UtilFree(buf);
2214          return TRUE;
2215       }
2216       UtilFree(buf);
2217    }
2218    return FALSE;
2219 }
2220 
2221 static
ReReadCmd(fp,start_file_pos,end_file_pos,pn_buf_len)2222 char *ReReadCmd(fp, start_file_pos, end_file_pos, pn_buf_len)
2223    FILE *fp;
2224    int start_file_pos, end_file_pos, *pn_buf_len;
2225 {
2226    char *buf=NULL;
2227    int ok=TRUE, buf_len=end_file_pos-start_file_pos;
2228 
2229    if (end_file_pos > start_file_pos) {
2230       buf_len = end_file_pos-start_file_pos;
2231 
2232       if (fseek(fp, start_file_pos, SEEK_SET) != 0) {
2233          fprintf(stderr,
2234                "Seek to %1d failed in UnpackCurrentTGWBState().\n",
2235                start_file_pos);
2236          ok = FALSE;
2237       } else {
2238          buf = (char*)malloc(buf_len+1);
2239          if (buf == NULL) FailAllocMessage();
2240          buf[buf_len] = '\0';
2241          if (buf_len != (int)fread(buf,
2242                sizeof(char), buf_len, fp)) {
2243             fprintf(stderr,
2244                   "Reading %1d bytes failed in %s.\n",
2245                   buf_len, "UnpackCurrentTGWBState()");
2246             ok = FALSE;
2247          }
2248       }
2249       if (ok && fseek(fp, start_file_pos, SEEK_SET) != 0) {
2250          fprintf(stderr,
2251                "Seek to %1d failed in UnpackCurrentTGWBState().\n",
2252                start_file_pos);
2253          ok = FALSE;
2254       }
2255    } else {
2256       fprintf(stderr,
2257             "Invalid (empty) cmd detected in UnpackCurrentTGWBState().\n");
2258       ok = FALSE;
2259    }
2260    if (!ok) {
2261       UtilFree(buf);
2262 
2263       return NULL;
2264    }
2265    if (pn_buf_len != NULL) *pn_buf_len = buf_len;
2266 
2267    return buf;
2268 }
2269 
2270 static
UnpackCurrentTGWBState(p_cur_state)2271 void UnpackCurrentTGWBState(p_cur_state)
2272     CurStatus *p_cur_state;
2273 {
2274    struct StkRec *stk_ptr=NULL;
2275    struct ObjRec *obj_ptr=NULL, *saved_top_obj=NULL, *saved_bot_obj=NULL;
2276    int read_status=TRUE, ok=TRUE, start_file_pos=0, end_file_pos=0;
2277    int content_length=0, do_inflate=FALSE, need_to_free_buf=FALSE;
2278    char *buf=p_cur_state->data, tmp_fname[MAXPATHLENGTH], content_type[80];
2279    char *buf_data_start=NULL;
2280    FILE *fp=NULL;
2281    struct CmdRec *cmd_ptr=NULL;
2282 
2283    *content_type = '\0';
2284    if (!GetContentInfoFromBuf(buf, content_type, sizeof(content_type),
2285          &content_length, &buf_data_start)) {
2286       sprintf(gszMsgBox, TgLoadString(STID_JOIN_WB_IN_FAILED_NO_CONTTYPE));
2287       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2288       return;
2289    }
2290    if (strcmp(content_type, "application/x-tgif-cmd-z") == 0) {
2291       if (!HasZlibSupport()) {
2292          sprintf(gszMsgBox, "%s %s.\n\nDeserialization aborted in %s.",
2293                TOOL_NAME, "is not compiled with ZLIB and cannot inflate()",
2294                "UnpackCurrentTGWBState()");
2295          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2296          return;
2297       } else {
2298          if (gstWBInfo.gz_listen_fp == NULL) {
2299             sprintf(gszMsgBox, "Cannot open '%s'.\n\n%s pid=%ld in %s.",
2300                   gstWBInfo.gz_listen_fname, "Deserialization aborted for",
2301                   gstWBInfo.pid, "UnpackCurrentTGWBState()");
2302             MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2303             return;
2304          }
2305          do_inflate = TRUE;
2306       }
2307    }
2308    if (do_inflate && HasZlibSupport()) {
2309       int rc=0, buf_sz=0;
2310 
2311       if (!DoInflate(buf_data_start, content_length, gstWBInfo.gz_listen_fp,
2312             TRUE, &rc)) {
2313          ZlibError(rc, FALSE);
2314          return;
2315       }
2316       buf_sz = (int)ftell(gstWBInfo.gz_listen_fp);
2317       buf = (char*)malloc(buf_sz+1);
2318       if (buf == NULL) FailAllocMessage();
2319       rewind(gstWBInfo.gz_listen_fp);
2320       if (fread(buf, sizeof(char), buf_sz, gstWBInfo.gz_listen_fp) !=
2321             buf_sz) {
2322          sprintf(gszMsgBox, "Cannot read %1d bytes from '%s'.\n\n%s for %s.",
2323                buf_sz, gstWBInfo.gz_listen_fname, "Deserialization aborted",
2324                "UnpackCurrentTGWBState()");
2325          MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2326          UtilFree(buf);
2327          return;
2328       }
2329       need_to_free_buf = TRUE;
2330    }
2331    if (MkTempFile(tmp_fname, sizeof(tmp_fname), tmpDir, TOOL_NAME) == NULL) {
2332       fprintf(stderr, TgLoadString(STID_CANT_CREATE_NAMED_TMP_FILE), tmp_fname);
2333       fprintf(stderr, "\n");
2334       if (need_to_free_buf) UtilFree(buf);
2335       return;
2336    }
2337    if ((fp=fopen(tmp_fname, "w+")) == NULL) {
2338       FailToOpenMessage(tmp_fname, "w", NULL);
2339       if (need_to_free_buf) UtilFree(buf);
2340       return;
2341    }
2342    writeFileFailed = FALSE;
2343 
2344 #ifdef _TGIF_DBG_WB2
2345    if (wb2DebugLevel == 0) {
2346       fprintf(stderr, "Received %1d bytes, pid = %ld\n", strlen(buf),
2347             gstWBInfo.pid);
2348    } else {
2349       fprintf(stderr, "<<<========================\n");
2350       fprintf(stderr, "%s\n", buf);
2351       fprintf(stderr, "<<<========================\n");
2352       fprintf(stderr, "Received %1d bytes, pid = %ld\n", strlen(buf),
2353             gstWBInfo.pid);
2354    }
2355    PrintFullIDsOfObjects("At the beginning of UnpackCurrentTGWBState()");
2356 #endif /* _TGIF_DBG_WB2 */
2357 
2358    writeFileFailed = FALSE;
2359    if (fprintf(fp, "%s", buf) == EOF) {
2360       writeFileFailed = TRUE;
2361    }
2362    if (writeFileFailed) {
2363       FailToWriteFileMessage(gstWBInfo.listen_fname);
2364       fclose(fp);
2365       unlink(tmp_fname);
2366       if (need_to_free_buf) UtilFree(buf);
2367       return;
2368    }
2369    stk_ptr = SaveFileInfo();
2370    ResetFileInfo();
2371    /* if (usePaperSizeStoredInFile) ResetOnePageSize(); */
2372 
2373    ResetDeserializeCmd();
2374 
2375    rewind(fp);
2376    importingFile = TRUE;
2377 
2378    strcpy(scanFileName, gstWBInfo.listen_fname);
2379    scanLineNum = 0;
2380    foundGoodStateObject = FALSE;
2381 
2382    seenCmdXInfo = FALSE;
2383    *content_type = '\0';
2384    ok = ReadPastWrapper(fp, NULL);
2385    while (ok && !seenCmdXInfo) {
2386       char *serialization_buf=NULL;
2387       int serialization_buf_len=0;
2388 
2389       DelAllPages();
2390       lastPageNum = 1;
2391       InitPage();
2392       readingPageNum = loadedCurPageNum = 0;
2393 
2394       ok = ReadPastHeader(fp, &start_file_pos);
2395       if (ok) {
2396          if (seenCmdXInfo) {
2397             break;
2398          }
2399          ok = ReadAheadOverACmd(fp, &end_file_pos);
2400          if (ok) {
2401             serialization_buf = ReReadCmd(fp, start_file_pos, end_file_pos,
2402                   &serialization_buf_len);
2403             if (serialization_buf == NULL) {
2404                ok = FALSE;
2405 #ifdef _TGIF_DBG_WB2
2406             } else {
2407                static int n=1;
2408 
2409                fprintf(stderr, "******* cmd %1d begin *******\n", n);
2410                fprintf(stderr, "%s", serialization_buf);
2411                fprintf(stderr, "******* cmd %1d end *******\n", n++);
2412 #endif /* _TGIF_DBG_WB2 */
2413             }
2414          }
2415       }
2416       if (ok) {
2417          while ((read_status=ReadObj(fp, &obj_ptr)) == TRUE) {
2418             if (obj_ptr != NULL) {
2419                fprintf(stderr,
2420                      "Unexpected objects read in UnpackCurrentTGWBState().\n");
2421             }
2422          }
2423          ok = CheckUnpackState(read_status);
2424          if (!ok) {
2425             DelAllObj();
2426          } else {
2427             saved_top_obj = topObj;
2428             saved_bot_obj = botObj;
2429             topObj = botObj = NULL;
2430          }
2431          DelAllPages();
2432          lastPageNum = 0;
2433          InitPage();
2434       }
2435       if (ok) {
2436          cmd_ptr = CreateCmdFromSerializedData(saved_top_obj, saved_bot_obj);
2437          if (cmd_ptr->type == CMD_MOVE) {
2438             cmd_ptr->subcmd =
2439                   (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
2440             if (cmd_ptr->subcmd == NULL) FailAllocMessage();
2441             memset(cmd_ptr->subcmd, 0, sizeof(struct SubCmdRec));
2442             cmd_ptr->subcmd->detail.move.dx =
2443                   gpDeserializeSubCmd->detail.move.dx;
2444             cmd_ptr->subcmd->detail.move.dy =
2445                   gpDeserializeSubCmd->detail.move.dy;
2446          } else if (cmd_ptr->type == CMD_WB_SLIDESHOW) {
2447             cmd_ptr->subcmd =
2448                   (struct SubCmdRec *)malloc(sizeof(struct SubCmdRec));
2449             if (cmd_ptr->subcmd == NULL) FailAllocMessage();
2450             memset(cmd_ptr->subcmd, 0, sizeof(struct SubCmdRec));
2451             cmd_ptr->subcmd->detail.slideshow.into_slideshow =
2452                   gpDeserializeSubCmd->detail.slideshow.into_slideshow;
2453          }
2454          if (cmd_ptr != NULL) {
2455             /* append */
2456             CopyAndInsertCmd(TRUE, serialization_buf, gstWBInfo.last_shadow_cmd,
2457                   NULL, cmd_ptr, &gstWBInfo.first_shadow_cmd,
2458                   &gstWBInfo.last_shadow_cmd);
2459             InsertCmd(gstWBInfo.last_cmd, NULL, cmd_ptr, &gstWBInfo.first_cmd,
2460                   &gstWBInfo.last_cmd);
2461          }
2462       }
2463 #ifdef _TGIF_DBG_WB2
2464       PrintFullIDsOfObjects("In UnpackCurrentTGWBState()");
2465 #endif /* _TGIF_DBG_WB2 */
2466       DeserializationCleanUp();
2467       ResetDeserializeCmd();
2468    }
2469    importingFile = FALSE;
2470 
2471    fclose(fp);
2472    unlink(tmp_fname);
2473 
2474    RestoreFileInfo(stk_ptr);
2475    ResetOnePageSize();
2476    free(stk_ptr);
2477 
2478    UpdPageStyle(pageStyle);
2479    /*
2480     * Now execute the commands!
2481     */
2482    if (ok) {
2483       gstWBInfo.cur_cmd = NULL;
2484       for (cmd_ptr=gstWBInfo.first_cmd; cmd_ptr != NULL;
2485             cmd_ptr=cmd_ptr->next) {
2486 #ifdef _TGIF_DBG_WB2
2487          DebugDumpCmd("--- Just before RedoACmd()",
2488                cmd_ptr->type, cmd_ptr->logical_clock,
2489                cmd_ptr->sender_process_id);
2490          PrintFullIDsOfObjects("\t");
2491 #endif /* _TGIF_DBG_WB2 */
2492          if (!RedoACmd(cmd_ptr, FALSE, TRUE)) {
2493             cmd_ptr->skipped = TRUE;
2494 #ifdef _TGIF_DBG_WB2
2495             DebugDumpCmd("=== Skip RedoACmd()",
2496                   cmd_ptr->type, cmd_ptr->logical_clock,
2497                   cmd_ptr->sender_process_id);
2498             PrintFullIDsOfObjects("\t");
2499 #endif /* _TGIF_DBG_WB2 */
2500             gstWBInfo.cur_cmd = cmd_ptr;
2501             break;
2502          } else {
2503 #ifdef _TGIF_DBG_WB2
2504             DebugDumpCmd("--- Just after RedoACmd()",
2505                   cmd_ptr->type, cmd_ptr->logical_clock,
2506                   cmd_ptr->sender_process_id);
2507             PrintFullIDsOfObjects("\t");
2508 #endif /* _TGIF_DBG_WB2 */
2509             if (topSel != NULL) RemoveAllSel();
2510          }
2511       }
2512       gstWBInfo.join_session_in_progress = TRUE;
2513    } else {
2514       CleanUpWBCmds();
2515       sprintf(gszMsgBox, TgLoadString(STID_JOIN_WB_IN_PROGRESS_FAILED));
2516       MsgBox(gszMsgBox, TOOL_NAME, INFO_MB);
2517    }
2518    if (need_to_free_buf) UtilFree(buf);
2519 }
2520 
HandleNewUserRequest()2521 void HandleNewUserRequest()
2522 {
2523    char buf[80];
2524    int buf_sz=sizeof(buf);
2525 
2526    /*
2527     * Get current tgwb state and establish
2528     *         a TCP conection to send the data.
2529     */
2530    int index=0;
2531 
2532    if (!gstWBInfo.do_whiteboard) {
2533       return;
2534    }
2535    for (index=0; index < buf_sz-1; index++) {
2536       if (read(talkToSelfFiledes[0], &buf[index], 1) != 1) {
2537          sprintf(gszMsgBox, TgLoadString(STID_READ_FROM_SELF_PIPE_FAIL), 1,
2538                TOOL_NAME),
2539          fprintf(stderr, "%s\n", gszMsgBox);
2540          index = (-1);
2541          break;
2542       } else if (buf[index] == '\0') {
2543          break;
2544       }
2545    }
2546    if (index == buf_sz-1) {
2547       sprintf(gszMsgBox, TgLoadString(STID_READ_FROM_SELF_PIPE_OVERFLOW),
2548             TOOL_NAME),
2549       fprintf(stderr, "%s\n", gszMsgBox);
2550       index = (-1);
2551    }
2552    if (index != (-1)) {
2553       int conn=0;
2554       CurStatus cur_state;
2555 
2556       memset(&cur_state, 0, sizeof(CurStatus));
2557       sscanf(buf, "%d", &conn);
2558       serializingFile = TRUE;
2559       PackCurrentTGWBState(&cur_state);
2560       serializingFile = FALSE;
2561       if (cur_state.size != 0) {
2562          RM_sendCurStatus(conn, (char*)cur_state.data, cur_state.size);
2563          UtilFree(cur_state.data);
2564       }
2565    }
2566 }
2567 
2568 /* =================== SIGPOLL Handler function =================== */
2569 
2570 /* #define DEBUG0 */
2571 
2572 #if (defined(PTHREAD) || defined(HAVE_LIBPTHREAD))
2573 static
ReceivePacket(void * arg)2574 void *ReceivePacket( void *arg )
2575 {
2576     while( 1 )
2577     {
2578         char *buf=NULL, *aux=NULL, id[300];
2579         int byread=0;
2580         struct SegmentationPack pack1;
2581 
2582         if( (byread = RM_recv(gstWBInfo.MCastSock, (char*) &pack1, sizeof(struct SegmentationPack))) > 0 )
2583         {
2584             char *buffer1=NULL;
2585 
2586 #ifdef DEBUG0
2587             fprintf(stdout, "__________# of received packet: %u of %u\n", ntohl(pack1.NumSeq), ntohl(pack1.NumPackets));
2588 #endif
2589             if( (buffer1 = DeSegment( pack1, &byread )) != NULL ){
2590                     buf = (char *)malloc( byread + 1 );
2591                     memcpy( buf, buffer1, byread );
2592                     buf[byread]= '\0';
2593                     free(buffer1);
2594 #ifdef DEBUG0
2595                     fprintf(stdout, "******Desegmentation OK\n");
2596 #endif
2597             }
2598             else
2599             {
2600                 continue;
2601             }
2602         } else if (byread == 0)
2603         {
2604              continue;
2605         }
2606         else {
2607              /* on error, break - no more messages to receive  (shutting down) */
2608              break;
2609         }
2610 
2611         /*
2612          * check if the message is from itself
2613          */
2614 
2615 
2616         if (strncmp(buf, "From: ", 6) != 0 || sscanf(&buf[6], "%s\r\n", id) != 1) {
2617            fprintf(stderr, "%s.  %s, pid = %ld=tid=%s.\nbuf=%s.\n",
2618                  "Fatal error", "Cannot find the sender id in IO_SignalHandler()",
2619                  gstWBInfo.pid, id, buf);
2620            free(buf);
2621            continue;
2622         }
2623 
2624         if(strcmp(id, gszLocalPID) == 0) {
2625            continue;
2626         }
2627 
2628 #ifdef DEBUG0
2629         /* Verify if either the command may be processed right now, or if it should be stored */
2630         fprintf(stderr,"Process the comand now? ");
2631 #endif
2632 
2633         if ((aux = (char *)malloc( byread + 1 )) == NULL)
2634         {
2635          fprintf(stderr,"Allocation error. (ReceivePacket)\n");
2636          exit(1);
2637         }
2638         strncpy(aux, buf, byread);
2639         aux[byread] = (char)0;
2640         buff_ins(gstWBInfo.bd_commands, aux);
2641         free(aux);
2642         free(buf);
2643 
2644         /*
2645          * Don't think we need this any more!
2646          *
2647          * if(gstWBInfo.BlockRemoteCmdDepth > 0) {
2648 
2649 #ifdef DEBUG
2650          *    buff_show(gstWBInfo.bd_commands);
2651 #endif
2652          *    continue;
2653          * }
2654          * else
2655          */
2656         {
2657             static char c='a';
2658 
2659             if (write(talkToSelfFiledes[1], &c, 1) != 1) {
2660                sprintf(gszMsgBox, TgLoadString(STID_WRITE_TO_SELF_PIPE_FAIL),
2661                      TOOL_NAME);
2662                fprintf(stderr, "%s\n", gszMsgBox);
2663             }
2664         }
2665     }
2666     return( NULL );
2667 }
2668 #endif /* (defined(PTHREAD) || defined(HAVE_LIBPTHREAD)) */
2669 
2670 /* =================== Init and CleanUp Functions =================== */
2671 
CleanUpWhiteBoard()2672 void CleanUpWhiteBoard()
2673 {
2674    int i=0;
2675 
2676    if (!gstWBInfo.do_whiteboard) {
2677       return;
2678    }
2679    snprintf(gszMsgBox, sizeof(gszMsgBox), "****%s**** ",
2680          TgLoadString(STID_SHUTTING_DOWN_WHITEBOARD));
2681    Msg(gszMsgBox);
2682 
2683    RM_leaveGroup( gstWBInfo.MCastSock, (char*)RM_USE_CURRENT_CONFIG );
2684    fprintf(stderr, "%s ", gszMsgBox);
2685    for (i=0; i < 10; i++) {
2686       fprintf(stderr, ".");
2687       MillisecondSleep(100);
2688    }
2689    fprintf(stderr, "\n");
2690    RMCastCleanUp();
2691    buff_destroy(gstWBInfo.bd_commands);
2692 
2693    CleanUpWBSockets();
2694    CleanUpWBCmds();
2695    memset(&gstWBInfo, 0, sizeof(struct WhiteBoardRec));
2696 
2697    CleanUpDeserializeCmd();
2698    buff_cleanup();
2699 }
2700 
handler(int a)2701 void handler(int a)
2702 {
2703    fprintf(stderr,"alarm catched in wb.c\n");
2704    exit(1);
2705 }
2706 
InitWhiteBoard()2707 int InitWhiteBoard()
2708 {
2709    InitLocalPID(); /* initializes gszLocalPID */
2710 
2711    memset(&gstWBInfo, 0, sizeof(struct WhiteBoardRec));
2712 
2713    gstWBInfo.BlockRemoteCmdDepth = 1; /* FIXME Should be zero? */
2714    gstWBInfo.pid = (long)getpid();
2715 
2716    if (cmdLineWb2) {
2717       gstWBInfo.do_whiteboard = TRUE;
2718    }
2719    if (cmdLineNoWhiteBoard) gstWBInfo.do_whiteboard = FALSE;
2720 
2721    *gstWBInfo.send_fname = *gstWBInfo.gz_send_fname = '\0';
2722    gstWBInfo.send_fp = gstWBInfo.gz_send_fp = NULL;
2723    gstWBInfo.send_socket = (-1);
2724 
2725    gstWBInfo.listening = FALSE;
2726 
2727    *gstWBInfo.listen_fname = *gstWBInfo.gz_listen_fname = '\0';
2728    gstWBInfo.listen_fp = gstWBInfo.gz_listen_fp = NULL;
2729    gstWBInfo.listen_socket = (-1);
2730 
2731 #ifdef _TGIF_DBG_WB2
2732    {
2733       char *c_ptr=NULL;
2734 
2735       wb2DebugLevel = 0;
2736       if ((c_ptr=XGetDefault(mainDisplay, TOOL_NAME, "DebugWB2")) != NULL) {
2737          wb2DebugLevel = atoi(c_ptr);
2738       }
2739    }
2740 #endif /* _TGIF_DBG_WB2 */
2741 
2742    memset(&gRMCastIntrfInfo, 0, sizeof(RMCastIntrfInfo));
2743 
2744    return TRUE;
2745 }
2746 
InitWhiteBoard2()2747 int InitWhiteBoard2()
2748 {
2749    int want_new_member_support=0;
2750 #if (defined(PTHREAD) || defined(HAVE_LIBPTHREAD))
2751    pthread_t tid=(pthread_t)0;
2752 #endif /* (defined(PTHREAD) || defined(HAVE_LIBPTHREAD)) */
2753    char tgwb_config_file[255];
2754    char *homedir=NULL;
2755    int config_ok=0;
2756 
2757    if (!gstWBInfo.do_whiteboard) return TRUE;
2758 
2759 #if (!defined(PTHREAD) && !defined(HAVE_LIBPTHREAD))
2760    sprintf(gszMsgBox, TgLoadString(STID_NO_PTHREAD_CONTINUE), TOOL_NAME,
2761          TOOL_NAME, TOOL_NAME);
2762    MsgBox(gszMsgBox, TOOL_NAME, STOP_MB);
2763    gstWBInfo.do_whiteboard = FALSE;
2764    SendCommandToSelf(CMDID_QUIT, 0);
2765    return FALSE;
2766 #endif /* (!defined(PTHREAD) && !defined(HAVE_LIBPTHREAD)) */
2767 
2768    if (!RMCastInit()) {
2769       gstWBInfo.do_whiteboard = FALSE;
2770       return FALSE;
2771    }
2772    InitDeserializeCmd();
2773 
2774    if (!CreateWBListenSocket()) {
2775       CleanUpWBSockets();
2776       exit(-1);
2777    }
2778 
2779    if (MkTempFile(gstWBInfo.send_fname, sizeof(gstWBInfo.send_fname),
2780          tmpDir, TOOL_NAME) == NULL) {
2781       fprintf(stderr, "Fail to create '%s' for serialization.\n",
2782             gstWBInfo.send_fname);
2783       exit(-1);
2784    }
2785    snprintf(gstWBInfo.gz_send_fname, sizeof(gstWBInfo.gz_send_fname),
2786          "%s.z", gstWBInfo.send_fname);
2787    if ((gstWBInfo.send_fp=fopen(gstWBInfo.send_fname, "w+")) == NULL) {
2788       fprintf(stderr, "Fail to create '%s' for serialization.\n",
2789             gstWBInfo.send_fname);
2790       exit(-1);
2791    }
2792    if ((gstWBInfo.gz_send_fp=fopen(gstWBInfo.gz_send_fname, "w+")) == NULL) {
2793       fprintf(stderr, "Fail to create '%s' for serialization.\n",
2794             gstWBInfo.gz_send_fname);
2795       exit(-1);
2796    }
2797 
2798    if ( (homedir=getenv("HOME")) != NULL ){
2799      sprintf(tgwb_config_file,"%s/.tgwb/tgwb.conf",homedir);
2800      if (RM_readConfigFile(tgwb_config_file, 0))
2801           config_ok=2; /* It means that we read $HOME/.tgwb/tgwb.conf */
2802    }
2803    else{
2804       fprintf(stderr,"TGWB Warning: Can't get environment variable 'HOME', using default values.\n");
2805    }
2806    if (config_ok==0 && RM_readConfigFile("/etc/tgwb.conf", 0)){
2807         config_ok=1; /* It means that we read /etc/tgwb.conf */
2808    }
2809 
2810    switch (config_ok){
2811       case 1:
2812          fprintf(stderr,"Using config file: '/etc/tgwb.conf'\n");
2813          break;
2814       case 2:
2815          fprintf(stderr,"Using config file: '%s'\n",tgwb_config_file);
2816          break;
2817       default:
2818          fprintf(stderr,"TGWB Warning:\n Config files:\n\t'%s/.tgwb/tgwb.conf'\n\t'/etc/tgwb.conf'\n not found.\nUsing default values.\n",homedir);
2819    }
2820 
2821    /* setting defaults */
2822 
2823    RM_setOption(PIPE, &talkToSelfFiledes);
2824    RM_setOption(SHUT_DOWN_ROUTINE, &CleanUpWBSockets);
2825 
2826    RM_initialize((void *)RMcallback_terminate);
2827 
2828    RM_getOption(NEW_MEMBER_SUPPORT, (void*)&want_new_member_support);
2829 
2830    if (want_new_member_support)
2831    {
2832         CurStatus cur_state;
2833 
2834         fprintf(stderr,"Getting the current status.\n");
2835 
2836         RM_getCurStatus( (char*)RM_USE_CURRENT_CONFIG, RM_USE_CURRENT_CONFIG,
2837                 &cur_state);
2838 
2839         if (cur_state.size != -1)
2840         {
2841             int saved_disable_redraw=disableRedraw;
2842 
2843             deserializingFile = TRUE;
2844             disableRedraw = TRUE;
2845             UnpackCurrentTGWBState(&cur_state);
2846             disableRedraw = saved_disable_redraw;
2847             if (!saved_disable_redraw) {
2848                ClearAndRedrawDrawWindow();
2849             }
2850             deserializingFile = FALSE;
2851         }
2852    }
2853    gstWBInfo.MCastSock = RM_joinGroup((char*)RM_USE_CURRENT_CONFIG, RM_USE_CURRENT_CONFIG );
2854 
2855    gstWBInfo.bd_commands = buff_init (10, WB_PACK, UNSORTED, NULL );
2856 
2857 /* debugging RMCAST
2858    fprintf(stderr,"buffer descriptor: %d\n", gstWBInfo.bd_commands);
2859 */
2860 #if (defined(PTHREAD) || defined(HAVE_LIBPTHREAD))
2861    if( pthread_create( &tid, NULL, ReceivePacket, NULL ) != 0 )
2862    {
2863        fprintf( stderr, "Could not create receive thread\n" );
2864        exit( -1 );
2865    }
2866 #endif /* (defined(PTHREAD) || defined(HAVE_LIBPTHREAD)) */
2867    return TRUE;
2868 }
2869 
RMcallback_terminate(void)2870 void RMcallback_terminate( void )
2871 {
2872     /*
2873      * tgif must do its clean up here before exit
2874      *
2875      * exit(0);
2876      */
2877 }
2878 
2879