1 /*
2  *
3  * XASTIR, Amateur Station Tracking and Information Reporting
4  * Copyright (C) 1999,2000  Frank Giannandrea
5  * Copyright (C) 2000-2019 The Xastir Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Look at the README for more information on the program.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25   #include "config.h"
26 #endif  // HAVE_CONFIG_H
27 
28 #include "snprintf.h"
29 
30 #include <Xm/XmAll.h>
31 #include <X11/Xatom.h>
32 #include <X11/Shell.h>
33 
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #ifdef HAVE_STRING_H
41   #include <string.h>
42 #else
43   #include <strings.h>
44 #endif
45 #include <ctype.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
48 
49 #if TIME_WITH_SYS_TIME
50   #include <sys/time.h>
51   #include <time.h>
52 #else   // TIME_WITH_SYS_TIME
53   #if HAVE_SYS_TIME_H
54     #include <sys/time.h>
55   #else  // HAVE_SYS_TIME_H
56     #include <time.h>
57   #endif // HAVE_SYS_TIME_H
58 #endif  // TIME_WITH_SYS_TIME
59 
60 #include "xastir.h"
61 #include "main.h"
62 #include "messages.h"
63 #include "util.h"
64 #include "interface.h"
65 #include "xa_config.h"
66 
67 // Must be last include file
68 #include "leak_detection.h"
69 
70 
71 
72 char group_data_file[400];
73 char *group_data_list = NULL;   // Need this NULL for Solaris!
74 int  group_data_count = 0;
75 int  group_data_max = 0;
76 
77 char message_counter[5+1];
78 
79 int auto_reply;
80 char auto_reply_message[100];
81 
82 Message_Window mw[MAX_MESSAGE_WINDOWS+1];   // Send Message widgets
83 
84 Message_transmit message_pool[MAX_OUTGOING_MESSAGES+1]; // Transmit message queue
85 
86 
87 
88 
89 
clear_message_windows(void)90 void clear_message_windows(void)
91 {
92   int i;
93 
94   begin_critical_section(&send_message_dialog_lock, "messages.c:clear_message_windows" );
95 
96   for (i = 0;  i < MAX_MESSAGE_WINDOWS; i++)
97   {
98 
99     if (mw[i].send_message_dialog)
100     {
101       XtDestroyWidget(mw[i].send_message_dialog);
102     }
103 
104     mw[i].send_message_dialog = (Widget)NULL;
105     mw[i].to_call_sign[0] = '\0';
106     mw[i].send_message_call_data = (Widget)NULL;
107     mw[i].D700_mode = (Widget)NULL;
108     mw[i].D7_mode = (Widget)NULL;
109     mw[i].HamHUD_mode = (Widget)NULL;
110     mw[i].message_data_line1 = (Widget)NULL;
111     mw[i].message_data_line2 = (Widget)NULL;
112     mw[i].message_data_line3 = (Widget)NULL;
113     mw[i].message_data_line4 = (Widget)NULL;
114     mw[i].send_message_text = (Widget)NULL;
115   }
116 
117   end_critical_section(&send_message_dialog_lock, "messages.c:clear_message_windows" );
118 
119 }
120 
121 
122 
123 
124 
group_comp(const void * a,const void * b)125 static int group_comp(const void *a, const void *b)
126 {
127   if (!*(char *)a)
128   {
129     return ((int)(*(char *)b != '\0'));
130   }
131   return strcasecmp(a, b);
132 }
133 
134 
135 
136 
137 
group_build_list(char * filename)138 void group_build_list(char *filename)
139 {
140   char *ptr;
141   FILE *f;
142   struct stat group_stat;
143   int i;
144 
145   if (group_data_count == group_data_max)
146   {
147     ptr = realloc(group_data_list, (size_t)(group_data_max+10)*10);
148 
149     if (ptr)
150     {
151       group_data_list = ptr;
152       group_data_max += 10;
153 
154 //fprintf(stderr,                "group_data_max: %d\n", group_data_max);
155 
156     }
157     else
158     {
159       fprintf(stderr,
160               "Unable to allocate more memory for group_data_list (1)\n");
161     }
162   }
163 
164 
165 // Make sure we always listen for ourself, XASTIR, & our Version groups
166   xastir_snprintf(&group_data_list[0],10,"%s",my_callsign);
167   xastir_snprintf(&group_data_list[10],10,"XASTIR");
168   xastir_snprintf(&group_data_list[20],10,"%s",XASTIR_TOCALL);
169   group_data_count = 3;
170 // If we are in special group look for messages.
171   if (altnet)
172   {
173     xastir_snprintf(&group_data_list[group_data_count*10],10,"%s",altnet_call);
174     group_data_count++;
175   }
176 //
177 
178   if (! stat(filename, &group_stat) )
179   {
180     f = fopen(filename, "r");  // File exists
181   }
182   else
183   {
184     f = fopen(filename, "w+");  // No file.  Create it and open it.
185   }
186 
187   if (f == NULL)
188   {
189     fprintf(stderr,"Couldn't open file for reading -or- appending: %s\n", filename);
190     return;
191   }
192 
193   while (!feof(f))
194   {
195     if (group_data_count == group_data_max)
196     {
197       ptr = realloc(group_data_list, (size_t)(group_data_max+10)*10);
198       if (ptr)
199       {
200         group_data_list = ptr;
201         group_data_max += 10;
202 
203 //fprintf(stderr,                "group_data_max(2): %d\n", group_data_max);
204 
205       }
206       else
207       {
208         fprintf(stderr,
209                 "Unable to allocate more memory for group_data_list (2)\n");
210       }
211     }
212     if (group_data_count < group_data_max)
213     {
214       group_data_list[group_data_count*10] = '\0';
215       if (fgets(&group_data_list[group_data_count*10], 10, f) == NULL)
216       {
217         // Error reading file or end-of-file. Continue processing
218         // the (partial?) string we just read, in the code below.
219       }
220       if ((ptr = strchr(&group_data_list[group_data_count*10], '\n')))
221       {
222         *ptr = '\0';
223       }
224       else
225         while ((i = fgetc(f)) != EOF && i != '\n'); // clean-up after long group name
226 
227       // check for DOS EOL markup!
228       if ((ptr = strchr(&group_data_list[group_data_count*10], '\r')))
229       {
230         *ptr = '\0';
231       }
232       if (group_data_list[group_data_count*10])
233       {
234         group_data_count++;
235       }
236     }
237   }
238   (void)fclose(f);
239   qsort(group_data_list, (size_t)group_data_count, 10, group_comp);
240 
241   if (debug_level & 2)
242   {
243     for (i = 0; i < group_data_count; i++)
244     {
245       fprintf(stderr,"Group %2d: %s\n", i, &group_data_list[i*10]);
246     }
247   }
248 }
249 
250 
251 
252 
253 
group_active(char * from)254 int group_active(char *from)
255 {
256   static struct stat current_group_stat;
257   struct stat group_stat;
258   static char altgroup[10];
259   char group_data_path[MAX_VALUE];
260 
261   get_user_base_dir(group_data_file, group_data_path,
262                     sizeof(group_data_path));
263 
264   (void)remove_trailing_spaces(from);
265 
266   // If we cycle to/from special group or file changes, rebuild group list.
267   if ((!stat( group_data_path, &group_stat )
268        && (current_group_stat.st_size != group_stat.st_size
269            || current_group_stat.st_mtime != group_stat.st_mtime
270            || current_group_stat.st_ctime != group_stat.st_ctime)))
271   {
272 
273 // altgroup equates to "address of altgroup" which always evaluates
274 // as true.  Commenting it out of the conditional.  --we7u.
275 //                || (altgroup && strcasecmp(altgroup, VERSIONFRM))) {
276 
277     group_build_list( group_data_path );
278     current_group_stat = group_stat;
279     xastir_snprintf(altgroup,sizeof(altgroup),"%s",VERSIONFRM);
280   }
281   if (group_data_list != NULL)    // Causes segfault on Solaris 2.5 without this!
282   {
283     return (int)(bsearch(from, group_data_list, (size_t)group_data_count, (size_t)10, group_comp) != NULL);
284   }
285   else
286   {
287     return(0);
288   }
289 }
290 
291 
292 
293 
294 
look_for_open_group_data(char * to)295 int look_for_open_group_data(char *to)
296 {
297   int i,found;
298   char temp1[MAX_CALLSIGN+1];
299   char *temp_ptr;
300 
301 
302   begin_critical_section(&send_message_dialog_lock, "messages.c:look_for_open_group_data" );
303 
304   found = FALSE;
305   for(i = 0; i < MAX_MESSAGE_WINDOWS; i++)
306   {
307     /* find station  */
308     if(mw[i].send_message_dialog != NULL)
309     {
310 
311       temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data);
312       xastir_snprintf(temp1,
313                       sizeof(temp1),
314                       "%s",
315                       temp_ptr);
316       XtFree(temp_ptr);
317 
318       (void)to_upper(temp1);
319       /*fprintf(stderr,"Looking at call <%s> for <%s>\n",temp1,to);*/
320       if(strcmp(temp1,to)==0)
321       {
322         found=(int)TRUE;
323         break;
324       }
325     }
326   }
327 
328   end_critical_section(&send_message_dialog_lock, "messages.c:look_for_open_group_data" );
329 
330   return(found);
331 }
332 
333 
334 
335 
336 
337 // What we wish to do here:  Check for an active Send Message dialog
338 // that contains the callsign of interest.  If one doesn't exist,
339 // create one and pop it up.  We don't want to do this for duplicate
340 // message lines or duplicate acks for any particular QSO.  To do so
341 // would cause the Send Message dialog to pop up on every such
342 // received message, which is VERY annoying (that was the default in
343 // Xastir for years, and nobody liked it!).
344 //
check_popup_window(char * from_call_sign,int group)345 int check_popup_window(char *from_call_sign, int group)
346 {
347   int i,found,j,ret;
348   char temp1[MAX_CALLSIGN+1];
349   char *temp_ptr;
350 
351 
352 //fprintf(stderr,"\tcheck_popup_window()\n");
353 
354   ret = -1;
355   found = -1;
356 
357   begin_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window" );
358 
359   // Check for an already-created dialog for talking to this
360   // particular call_sign.
361   //
362   for (i = 0; i < MAX_MESSAGE_WINDOWS; i++)
363   {
364 
365     if (mw[i].send_message_dialog != NULL)   // If dialog created
366     {
367 
368       temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data);
369       xastir_snprintf(temp1,
370                       sizeof(temp1),
371                       "%s",
372                       temp_ptr);
373       XtFree(temp_ptr);
374 
375       /*fprintf(stderr,"Looking at call <%s> for <%s>\n",temp1,from_call_sign);*/
376       if (strcasecmp(temp1, from_call_sign) == 0)
377       {
378         // Found a call_sign match in a Send Message dialog!
379 
380 //fprintf(stderr,"\tFound a Send_message dialog match\n");
381 
382         found = i;
383         break;
384       }
385     }
386   }
387 
388   end_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window" );
389 
390   // If found == -1 at this point, we haven't found a Send Message
391   // dialog that contains the call_sign of interest.
392   //
393   if (found == -1 && (group == 2 || group_active(from_call_sign)))
394   {
395     /* no window found Open one! */
396 
397 //fprintf(stderr,"\tNo Send Message dialog found, creating one\n");
398 
399     begin_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window2" );
400 
401     i= -1;
402     for (j=0; j<MAX_MESSAGE_WINDOWS; j++)
403     {
404       if (!mw[j].send_message_dialog)
405       {
406         i=j;
407         break;
408       }
409     }
410 
411     end_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window2" );
412 
413     if (i!= -1)
414     {
415 
416       if (group == 1)
417       {
418         temp1[0] = '*';
419         temp1[1] = '\0';
420       }
421       else
422       {
423         temp1[0] = '\0';
424       }
425 
426       strncat(temp1,
427               from_call_sign,
428               sizeof(temp1) - 1 - strlen(temp1));
429 
430       if (!disable_all_popups)
431       {
432         Send_message(appshell, temp1, NULL);
433       }
434 
435       update_messages(1);
436 
437       ret=i;
438     }
439     else
440     {
441       fprintf(stderr,"No open windows!\n");
442     }
443   }
444   else
445   {
446     /* window open! */
447     // Pop it up
448     ret=found;
449   }
450 
451   if (found != -1)    // Already have a window
452   {
453     XtPopup(mw[i].send_message_dialog,XtGrabNone);
454   }
455 
456   return(ret);
457 }
458 
459 
460 
461 
462 
clear_outgoing_message(int i)463 void clear_outgoing_message(int i)
464 {
465   message_pool[i].active=MESSAGE_CLEAR;
466   message_pool[i].to_call_sign[0] = '\0';
467   message_pool[i].from_call_sign[0] = '\0';
468   message_pool[i].message_line[0] = '\0';
469   message_pool[i].seq[0] = '\0';
470   message_pool[i].active_time=0;;
471   message_pool[i].next_time=0L;
472   message_pool[i].tries=0;
473 }
474 
475 
476 
477 
478 
479 // Clear all pending transmit messages that are from us and to the
480 // callsign listed.  Perhaps it'd be better to time it out instead
481 // so that it still shows up in the message window?  Here we just
482 // erase it.
483 //
clear_outgoing_messages_to(char * callsign)484 void clear_outgoing_messages_to(char *callsign)
485 {
486   int ii;
487 
488 
489 //    fprintf(stderr,"Callsign: %s\n", callsign);
490 
491   // Run through the entire outgoing message queue
492   for (ii = 0; ii < MAX_OUTGOING_MESSAGES; ii++)
493   {
494 
495     // If it matches the callsign we're talking to
496     if (strcasecmp(message_pool[ii].to_call_sign,callsign) == 0)
497     {
498 
499       // Record a fake ack and add "*CANCELLED*" to the
500       // message.  This will be displayed in the Send Message
501       // dialog.
502       msg_record_ack(message_pool[ii].to_call_sign,
503                      message_pool[ii].from_call_sign,
504                      message_pool[ii].seq,
505                      0,  // Not a timeout
506                      1); // Record a cancel
507 
508       // Clear it out.
509       message_pool[ii].active=MESSAGE_CLEAR;
510       message_pool[ii].to_call_sign[0] = '\0';
511       message_pool[ii].from_call_sign[0] = '\0';
512       message_pool[ii].message_line[0] = '\0';
513       message_pool[ii].seq[0] = '\0';
514       message_pool[ii].active_time=0;;
515       message_pool[ii].next_time=0L;
516       message_pool[ii].tries=0;
517     }
518   }
519 }
520 
521 
522 
523 
524 
525 // Change path on all pending transmit messages that are from us and
526 // to the callsign listed.
527 //
change_path_outgoing_messages_to(char * callsign,char * new_path)528 void change_path_outgoing_messages_to(char *callsign, char *new_path)
529 {
530   int ii;
531   char my_callsign[20];
532 
533 
534 //fprintf(stderr,
535 //    "Changing all outgoing msgs to %s to new path: %s\n",
536 //    callsign,
537 //    new_path);
538 
539   xastir_snprintf(my_callsign,
540                   sizeof(my_callsign),
541                   "%s",
542                   callsign);
543 
544   remove_trailing_spaces(my_callsign);
545 
546   // Run through the entire outgoing message queue
547   for (ii = 0; ii < MAX_OUTGOING_MESSAGES; ii++)
548   {
549 
550     if (message_pool[ii].active == MESSAGE_ACTIVE)
551     {
552 
553 //fprintf(stderr,"\t'%s'\n\t'%s'\n",
554 //    message_pool[ii].to_call_sign,
555 //    my_callsign);
556 
557       // If it matches the callsign we're talking to
558       if (strcasecmp(message_pool[ii].to_call_sign,my_callsign) == 0)
559       {
560 
561 //fprintf(stderr,"\tFound an outgoing queued msg to change path on.\n");
562 
563         xastir_snprintf(message_pool[ii].path,
564                         sizeof(message_pool[ii].path),
565                         "%s",
566                         new_path);
567       }
568     }
569   }
570 }
571 
572 
573 
574 
575 
576 time_t last_check_and_transmit = (time_t)0L;
577 
578 
579 // Kick the interval timer back to 7 and tries back to 1 for
580 // messages in this QSO.  Used to get a QSO going again when the
581 // interval timer has gotten large, but the message is important to
582 // get through quickly.
583 //
kick_outgoing_timer(char * callsign)584 void kick_outgoing_timer(char *callsign)
585 {
586   int ii;
587 
588 
589 //    fprintf(stderr,"Callsign: %s\n", callsign);
590 
591   // Run through the entire outgoing message queue
592   for (ii = 0; ii < MAX_OUTGOING_MESSAGES; ii++)
593   {
594 
595     // If it matches the callsign we're talking to
596     if (strcasecmp(message_pool[ii].to_call_sign,callsign) == 0)
597     {
598       message_pool[ii].next_time = (time_t)7L;
599       message_pool[ii].tries = 0;
600       message_pool[ii].active_time = (time_t)0L;
601     }
602   }
603 
604   // Cause the transmit routine to get called again
605   last_check_and_transmit = (time_t)0L;
606 }
607 
608 
609 
610 
611 
reset_outgoing_messages(void)612 void reset_outgoing_messages(void)
613 {
614   int i;
615 
616   for(i=0; i<MAX_OUTGOING_MESSAGES; i++)
617   {
618     clear_outgoing_message(i);
619   }
620 }
621 
622 
623 
624 
625 
clear_outgoing_messages(void)626 void clear_outgoing_messages(void)
627 {
628   int i;
629 
630   for (i=0; i<MAX_OUTGOING_MESSAGES; i++)
631   {
632     clear_outgoing_message(i);
633   }
634 
635   begin_critical_section(&send_message_dialog_lock, "messages.c:clear_outgoing_messages" );
636 
637   /* clear message send buttons */
638   for (i=0; i<MAX_MESSAGE_WINDOWS; i++)
639   {
640     /* find station  */
641 //        if (mw[i].send_message_dialog!=NULL) /* clear submit */
642 //            XtSetSensitive(mw[i].button_ok,TRUE);
643   }
644 
645   end_critical_section(&send_message_dialog_lock, "messages.c:clear_outgoing_messages" );
646 
647 }
648 
649 
650 
651 
652 
653 // Bumps message sequence ID up to the next value.
654 //
655 // Roll over message_counter if we hit the max.  Now with Reply/Ack
656 // protocol the max is only two characters worth.  We changed to
657 // sending the sequence number in Base-?? format in order to get
658 // more range from the 2-character variable.
659 //
bump_message_counter(char * message_counter)660 int bump_message_counter(char *message_counter)
661 {
662 
663   int bump_warning = 0;
664   message_counter[2] = '\0';  // Terminate at 2 chars
665 
666   // Increment the least significant digit
667   message_counter[1]++;
668 
669   // Span the gaps between the correct ranges
670   if (message_counter[1] == ':')
671   {
672     message_counter[1] = 'A';
673   }
674 
675   if (message_counter[1] == '[')
676   {
677     message_counter[1] = 'a';
678   }
679 
680   if (message_counter[1] == '{')
681   {
682     message_counter[1] = '0';
683     message_counter[0]++;   // Roll over to next char
684   }
685 
686   // Span the gaps between the correct ranges
687   if (message_counter[0] == ':')
688   {
689     message_counter[0] = 'A';
690   }
691 
692   if (message_counter[0] == '[')
693   {
694     message_counter[0] = 'a';
695   }
696 
697   if (message_counter[0] == '{')
698   {
699     message_counter[0] = '0';
700     bump_warning = 1;
701   }
702   return bump_warning;
703 }
704 
705 
706 
707 
708 
709 // Adds a message to the outgoing message queue.  Doesn't actually
710 // cause a transmit.  "check_and_transmit_messages()" is the
711 // function which actually gets things moving.
712 //
713 // We also stuff the message into the main message queue so that the
714 // queued messages will appear in the Send Message box.
715 //
output_message(char * from,char * to,char * message,char * path)716 void output_message(char *from, char *to, char *message, char *path)
717 {
718   int ok,i,j;
719   char message_out[MAX_MESSAGE_OUTPUT_LENGTH+1+5+1]; // +'{' +msg_id +terminator
720   int last_space, message_ptr, space_loc;
721   int wait_on_first_ack;
722   int error;
723   long record;
724 
725 
726 //fprintf(stderr,"output_message:%s\n", message);
727 
728   message_ptr=0;
729   last_space=0;
730   ok=0;
731   error=0;
732 
733   if (debug_level & 2)
734   {
735     fprintf(stderr,"Output Message from <%s>  to <%s>\n",from,to);
736   }
737 
738   // Repeat until we process the entire message.  We'll process it
739   // a chunk at a time, size of chunk to correspond to max APRS
740   // message line length.
741   //
742   while (!error && (message_ptr < (int)strlen(message)))
743   {
744     ok=0;
745     space_loc=0;
746 
747     // Break a long message into smaller chunks that can be
748     // processed into APRS messages.  Break at a space character
749     // if possible.
750     //
751     for (j=0; j<MAX_MESSAGE_OUTPUT_LENGTH; j++)
752     {
753 
754       if(message[j+message_ptr] != '\0')
755       {
756 
757         if(message[j+message_ptr]==' ')
758         {
759           last_space=j+message_ptr+1;
760           space_loc=j;
761         }
762 
763         if (j!=MAX_MESSAGE_OUTPUT_LENGTH)
764         {
765           message_out[j]=message[j+message_ptr];
766           message_out[j+1] = '\0';
767         }
768         else
769         {
770 
771           if(space_loc!=0)
772           {
773             message_out[space_loc] = '\0';
774           }
775           else
776           {
777             last_space=j+message_ptr;
778           }
779         }
780       }
781       else
782       {
783         j=MAX_MESSAGE_OUTPUT_LENGTH+1;
784         last_space=strlen(message)+1;
785       }
786     }
787 
788 //fprintf(stderr,"message_out: %s\n", message_out);
789 
790     if (debug_level & 2)
791     {
792       fprintf(stderr,"MESSAGE <%s> %d %d\n",message_out,message_ptr,last_space);
793     }
794 
795     if (j >= MAX_MESSAGE_OUTPUT_LENGTH)
796     {
797       message_ptr = MAX_MESSAGE_OUTPUT_LENGTH;
798     }
799     else
800     {
801       message_ptr=last_space;
802     }
803 
804     /* check for others in the queue */
805     wait_on_first_ack=0;
806     for (i=0; i<MAX_OUTGOING_MESSAGES; i++)
807     {
808       if (message_pool[i].active == MESSAGE_ACTIVE
809           && strcmp(to, message_pool[i].to_call_sign) == 0
810           && strcmp(from, "***") != 0)
811       {
812         wait_on_first_ack=1;
813         i=MAX_OUTGOING_MESSAGES+1;  // Done with loop
814       }
815     }
816 
817     for (i=0; i<MAX_OUTGOING_MESSAGES && !ok ; i++)
818     {
819       /* Check for clear position*/
820       if (message_pool[i].active==MESSAGE_CLEAR)
821       {
822         /* found a spot */
823         ok=1;
824 
825         // Increment the message sequence ID variable
826         if (bump_message_counter(message_counter))
827         {
828           fprintf(stderr, "!WARNING!: Wrap around Message Counter");
829         }
830 
831 
832 // Note that Xastir's messaging can lock up if we do a rollover and
833 // have unacked messages on each side of the rollover.  This is due
834 // to the logic in db.c that looks for the lowest numbered unacked
835 // message.  We get stuck on both sides of the fence at once.  To
836 // avoid this condition we could reduce the compare number (8100) to
837 // a smaller value, and only roll over when there are no unacked
838 // messages?  Another way to do it would be to write a "0" to the
839 // config file if we're more than 1000 when we quit Xastir?  That
840 // would probably be easier.  It's still possible to get to 8100
841 // messages during one runtime though.  Unlikely, but possible.
842 
843         message_pool[i].active = MESSAGE_ACTIVE;
844         message_pool[i].wait_on_first_ack = wait_on_first_ack;
845         xastir_snprintf(message_pool[i].to_call_sign,
846                         sizeof(message_pool[i].to_call_sign),
847                         "%s",
848                         to);
849         xastir_snprintf(message_pool[i].from_call_sign,
850                         sizeof(message_pool[i].from_call_sign),
851                         "%s",
852                         from);
853         memcpy(message_pool[i].message_line, message_out, sizeof(message_pool[i].message_line));
854         // Terminate line
855         message_pool[i].message_line[sizeof(message_pool[i].message_line)-1] = '\0';
856 
857         if (path != NULL)
858           xastir_snprintf(message_pool[i].path,
859                           sizeof(message_pool[i].path),
860                           "%s",
861                           path);
862         else
863         {
864           message_pool[i].path[0] = '\0';
865         }
866 
867 //                // We compute the base-90 sequence number here
868 //                // This allows it to range from "!!" to "zz"
869 //                xastir_snprintf(message_pool[i].seq,
870 //                    sizeof(message_pool[i].seq),
871 //                    "%c%c",
872 //                    (char)(((message_counter / 90) % 90) + 33),
873 //                    (char)((message_counter % 90) + 33));
874 
875         xastir_snprintf(message_pool[i].seq,
876                         sizeof(message_pool[i].seq),
877                         "%c%c",
878                         message_counter[0],
879                         message_counter[1]);
880 
881         message_pool[i].active_time=0;
882         message_pool[i].next_time = (time_t)7L;
883 
884         if (strcmp(from,"***")!= 0)
885         {
886           message_pool[i].tries = 0;
887         }
888         else
889         {
890           message_pool[i].tries = MAX_TRIES-1;
891         }
892 
893         // Cause the message to get added to the main
894         // message queue as well, with the proper sequence
895         // number, so queued messages will appear in the
896         // Send Message box as unacked messages.
897         //
898 
899 // We must get rid of the lock we already have for a moment, as
900 // update_messages(), which is called by msg_data_add(), also snags
901 // this lock.
902         end_critical_section(&send_message_dialog_lock, "db.c:update_messages" );
903 
904         (void)msg_data_add(to,
905                            from,
906                            message_out,
907                            message_pool[i].seq,
908                            MESSAGE_MESSAGE,
909                            'L',    // From the Local system
910                            &record);
911         /*
912                         fprintf(stderr,"msg_data_add %s %s %s %s\n",
913                             to,
914                             from,
915                             message_out,
916                             message_pool[i].seq);
917         */
918 
919 // Regain the lock we had before
920         begin_critical_section(&send_message_dialog_lock, "db.c:update_messages" );
921 
922       }
923     }
924     if(!ok)
925     {
926       fprintf(stderr,"Output message queue is full!\n");
927       error=1;
928     }
929   }
930 }
931 
932 
933 
934 
935 
936 // Here we're doing some routing of the transmitted packets.  We
937 // want to keep Xastir from transmitting on ports that aren't
938 // actively being used in the QSO, but also cover the case where
939 // ports can go up/down during the QSO.
940 //
941 // Note that igates might get into the act quite a bit for RF<->RF
942 // QSO's if we're sending to the internet too, but that's a bug in
943 // the igate software, and not something that Xastir should try to
944 // correct itself.
945 //
transmit_message_data(char * to,char * message,char * path)946 void transmit_message_data(char *to, char *message, char *path)
947 {
948   DataRow *p_station;
949 
950   if (debug_level & 2)
951   {
952     fprintf(stderr,"Transmitting data to %s : %s\n",to,message);
953   }
954 
955   p_station = NULL;
956 
957 
958   if (strcmp(to, my_callsign) == 0)   // My station message
959   {
960 
961     // Send out all active ports
962 
963     if (debug_level & 2)
964     {
965       fprintf(stderr,"My call VIA any way\n");
966     }
967 
968     output_my_data(message,-1,0,0,0,path);
969 
970     // All done
971     return;
972   }
973 
974 
975   if (!search_station_name(&p_station,to,1))
976   {
977 
978     // No data record found for this station.  Send to all
979     // active ports.
980 
981     if (debug_level & 2)
982     {
983       fprintf(stderr,"VIA any way\n");
984     }
985 
986     output_my_data(message,-1,0,0,0,path);
987 
988     // All done
989     return;
990   }
991 
992 
993   if (debug_level & 2)
994   {
995     fprintf(stderr,"found station %s\n",p_station->call_sign);
996   }
997 
998 
999   // It's not being sent to my callsign but to somebody else
1000   // "out there".  Because the truth is...
1001 
1002 
1003   if ( ((p_station->flag & ST_VIATNC) != 0)
1004        && (heard_via_tnc_in_past_hour(to)) )
1005   {
1006 
1007     int port_num;
1008 
1009 
1010     // Station was heard via a TNC port within the previous
1011     // hour.  Send to TNC port it was heard on.
1012     //
1013     output_my_data(message,p_station->heard_via_tnc_port,0,0,0,path);
1014 
1015     // Send to all internet ports.  Iterate through the port
1016     // definitions looking for internet ports, send the message
1017     // out once to each.
1018     //
1019     for (port_num = 0; port_num < MAX_IFACE_DEVICES; port_num++)
1020     {
1021 
1022       // If it's an internet port, send the message.
1023       if (port_data[port_num].device_type == DEVICE_NET_STREAM)
1024       {
1025         output_my_data(message,port_num,0,0,0,path);
1026       }
1027     }
1028 
1029     // All done
1030     return;
1031   }
1032 
1033   else if (p_station->data_via==DATA_VIA_NET)
1034   {
1035     int port_num;
1036     int active_internet_ports_found = 0;
1037 
1038 
1039     // Station was heard over an internet interface.  Check
1040     // whether we have any internet interfaces available with TX
1041     // enabled.  If so, send out those ports.  Else drop through
1042     // and hit the TRANSMIT-ALL clause at the end of this
1043     // function.
1044 
1045     // Iterate through the port definitions looking for internet
1046     // ports with transmit enabled.  Send the message out once
1047     // to each.
1048     //
1049     for (port_num = 0; port_num < MAX_IFACE_DEVICES; port_num++)
1050     {
1051 
1052       // If it's an internet port and transmit is enabled,
1053       // send the message and set the flag.
1054       if ( (port_data[port_num].device_type == DEVICE_NET_STREAM)
1055            && (port_data[port_num].active == DEVICE_IN_USE)
1056            && (port_data[port_num].status == DEVICE_UP)
1057            && (devices[port_num].transmit_data == 1) )
1058       {
1059 
1060         // Found a tx-enabled internet port that was up and
1061         // running.  Send the message out this port.
1062         output_my_data(message,port_num,0,0,0,path);
1063 
1064         active_internet_ports_found++;
1065       }
1066     }
1067 
1068     if (active_internet_ports_found)
1069     {
1070       // We found at least one tx-enabled internet interface
1071       // that was up and running.
1072 
1073       // All done.
1074       return;
1075     }
1076     else    // No active tx-enabled internet ports were found.
1077     {
1078       // Drop through to the TRANSMIT-ALL clause below.
1079     }
1080   }
1081 
1082 
1083   // We've NOT heard this station on a TNC port within the
1084   // last hour and have no active tx-enabled internet ports to
1085   // send to.  Send to ALL active ports.
1086 
1087   if (debug_level & 2)
1088   {
1089     fprintf(stderr,"VIA any way\n");
1090   }
1091 
1092   output_my_data(message,-1,0,0,0,path);
1093 }
1094 
1095 
1096 
1097 
1098 
1099 // The below variables and functions implement the capability to
1100 // schedule ACK's some number of seconds out from the current time.
1101 // We use it to schedule duplicate ACK's at 30/60/120 seconds out,
1102 // but only if we see duplicate message lines from remote stations.
1103 //
1104 // Create a struct to hold the delayed ack's.
1105 typedef struct _delayed_ack_record
1106 {
1107   char to_call_sign[MAX_CALLSIGN+1];
1108   char message_line[MAX_MESSAGE_OUTPUT_LENGTH+1+5+1];
1109   char path[200];
1110   time_t active_time;
1111   struct _delayed_ack_record *next;
1112 } delayed_ack_record, *delayed_ack_record_p;
1113 
1114 // And a pointer to a list of them.
1115 delayed_ack_record_p delayed_ack_list_head = NULL;
1116 
1117 
transmit_message_data_delayed(char * to,char * message,char * path,time_t when)1118 void transmit_message_data_delayed(char *to, char *message,
1119                                    char *path, time_t when)
1120 {
1121   delayed_ack_record_p ptr = delayed_ack_list_head;
1122 
1123 
1124   // We need to run down the current list looking for any records
1125   // that are identical and within 30 seconds time-wise of this
1126   // one.  If so, don't allocate a new record.  This keeps the
1127   // dupes down on transmit so that at the most we transmit one
1128   // ack per 30 seconds per QSO, except of course for real-time
1129   // ack's which don't go through this function.
1130 
1131   // Run through the queue and check each record
1132   while (ptr != NULL)
1133   {
1134 
1135     if ( strcmp(ptr->to_call_sign,to) == 0
1136          && strcmp(ptr->message_line,message) == 0 )
1137     {
1138 
1139       //
1140       // We have matches on call_sign and message.  Check the
1141       // time next.
1142       //
1143       if (labs(when - ptr->active_time) < 30)
1144       {
1145         //
1146         // We're within 30 seconds of an identical ack.
1147         // Drop this new one (don't add it).
1148         //
1149 
1150 //fprintf(stderr,"Dropping delayed ack: Too close timewise to another: %s, %s\n",
1151 //    to, message);
1152 
1153         return; // Don't allocate new record on queue
1154       }
1155     }
1156     ptr = ptr->next;
1157   }
1158 
1159   // If we made it to here, there aren't any queued ACK's that are
1160   // close enough in time to drop this new one.  Add it to the
1161   // queue.
1162 
1163 //fprintf(stderr, "Queuing ACK for delayed transmit: %s, %s\n",
1164 //    to, message);
1165 
1166   // Allocate a record to hold it
1167   ptr = (delayed_ack_record_p)malloc(sizeof(delayed_ack_record));
1168 
1169   // Fill in the record
1170   xastir_snprintf(ptr->to_call_sign,
1171                   sizeof(ptr->to_call_sign),
1172                   "%s",
1173                   to);
1174 
1175   xastir_snprintf(ptr->message_line,
1176                   sizeof(ptr->message_line),
1177                   "%s",
1178                   message);
1179 
1180   if (path == NULL)
1181   {
1182     ptr->path[0] = '\0';
1183   }
1184   else
1185   {
1186     xastir_snprintf(ptr->path,
1187                     sizeof(ptr->path),
1188                     "%s",
1189                     path);
1190   }
1191 
1192   ptr->active_time = when;
1193 
1194   // Add the record to the head of the list
1195   ptr->next = delayed_ack_list_head;
1196   delayed_ack_list_head = ptr;
1197 }
1198 
1199 
1200 
1201 
1202 
1203 time_t delayed_transmit_last_check = (time_t)0;
1204 
1205 
check_delayed_transmit_queue(int curr_sec)1206 void check_delayed_transmit_queue(int curr_sec)
1207 {
1208   delayed_ack_record_p ptr = delayed_ack_list_head;
1209   int active_records = 0;
1210 
1211 
1212   // Skip this function if we did it during this second already.
1213   if (delayed_transmit_last_check == curr_sec)
1214   {
1215     return;
1216   }
1217   delayed_transmit_last_check = curr_sec;
1218 
1219 //fprintf(stderr, "Checking delayed TX queue for something to transmit.\n");
1220 //fprintf(stderr, ".");
1221 
1222   // Run down the linked list checking every record.
1223   while (ptr != NULL)
1224   {
1225     if (ptr->active_time != 0)     // Active record
1226     {
1227       char new_path[MAX_LINE_SIZE+1];
1228 
1229 
1230 //fprintf(stderr, "Found active record\n");
1231 
1232       active_records++;
1233 
1234 
1235       // Check for a custom path having been set in the Send
1236       // Message dialog.  If so, use this for our outgoing
1237       // path instead and reset all of the queued message
1238       // paths to this station to this new path.
1239       //
1240       get_send_message_path(ptr->to_call_sign,
1241                             new_path,
1242                             sizeof(new_path));
1243 
1244       if (new_path[0] != '\0'
1245           && strcmp(new_path, ptr->path) != 0)
1246       {
1247 
1248         // We have a custom path set which is different than
1249         // the path saved with the outgoing message.  Change
1250         // the path to match the new path.
1251         //
1252 //fprintf(stderr,
1253 //    "Changing queued ack's to new path: %s\n",
1254 //    new_path);
1255 
1256         memcpy(ptr->path, new_path, sizeof(ptr->path));
1257         ptr->path[sizeof(ptr->path)-1] = '\0';  // Terminate string
1258       }
1259 
1260 
1261       if (ptr->active_time <= sec_now())
1262       {
1263         // Transmit it
1264 //fprintf(stderr,"Found something delayed to transmit!  %ld\n",sec_now());
1265 
1266         if (ptr->path[0] == '\0')
1267         {
1268           transmit_message_data(ptr->to_call_sign,
1269                                 ptr->message_line,
1270                                 NULL);
1271         }
1272         else
1273         {
1274           transmit_message_data(ptr->to_call_sign,
1275                                 ptr->message_line,
1276                                 ptr->path);
1277         }
1278 
1279         ptr->active_time = (time_t)0;
1280       }
1281     }
1282     ptr = ptr->next;
1283   }
1284 
1285   // Check if entire list contains inactive records.  If so,
1286   // delete the list.
1287   //
1288   if (!active_records && (delayed_ack_list_head != NULL))
1289   {
1290     // No active records, but the list isn't empty.  Reclaim the
1291     // records in the list.
1292     while (delayed_ack_list_head != NULL)
1293     {
1294       ptr = delayed_ack_list_head->next;
1295       free(delayed_ack_list_head);
1296 //fprintf(stderr,"Free'ing delayed_ack record\n");
1297       delayed_ack_list_head = ptr;
1298     }
1299   }
1300 }
1301 
1302 
1303 
1304 
1305 
check_and_transmit_messages(time_t time)1306 void check_and_transmit_messages(time_t time)
1307 {
1308   int i;
1309   char temp[200];
1310   char to_call[40];
1311 
1312 
1313   // Skip this function if we did it during this second already.
1314   if (last_check_and_transmit == time)
1315   {
1316     return;
1317   }
1318   last_check_and_transmit = time;
1319 
1320   for (i=0; i<MAX_OUTGOING_MESSAGES; i++)
1321   {
1322     if (message_pool[i].active==MESSAGE_ACTIVE)
1323     {
1324       if (message_pool[i].wait_on_first_ack!=1)   // Tx only if 0
1325       {
1326         if (message_pool[i].active_time < time)
1327         {
1328           char *last_ack_ptr;
1329           char last_ack[5+1];
1330 
1331 
1332           if (message_pool[i].tries < MAX_TRIES)
1333           {
1334             char new_path[MAX_LINE_SIZE+1];
1335 
1336 
1337             /* sending message let the tnc and net transmits check to see if we should */
1338             if (debug_level & 2)
1339               fprintf(stderr,
1340                       "Time %ld Active time %ld next time %ld\n",
1341                       (long)time,
1342                       (long)message_pool[i].active_time,
1343                       (long)message_pool[i].next_time);
1344 
1345             if (debug_level & 2)
1346               fprintf(stderr,"Send message#%d to <%s> from <%s>:%s-%s\n",
1347                       message_pool[i].tries,
1348                       message_pool[i].to_call_sign,
1349                       message_pool[i].from_call_sign,
1350                       message_pool[i].message_line,
1351                       message_pool[i].seq);
1352 
1353             pad_callsign(to_call,message_pool[i].to_call_sign);
1354 
1355             // Add Leading ":" as per APRS Spec.
1356             // Add trailing '}' to signify that we're
1357             // Reply/Ack protocol capable.
1358             last_ack_ptr = get_most_recent_ack(to_call);
1359             if (last_ack_ptr != NULL)
1360               xastir_snprintf(last_ack,
1361                               sizeof(last_ack),
1362                               "%s",
1363                               last_ack_ptr);
1364             else
1365             {
1366               last_ack[0] = '\0';
1367             }
1368 
1369             xastir_snprintf(temp, sizeof(temp), ":%s:%s{%s}%s",
1370                             to_call,
1371                             message_pool[i].message_line,
1372                             message_pool[i].seq,
1373                             last_ack);
1374 
1375             if (debug_level & 2)
1376             {
1377               fprintf(stderr,"MESSAGE OUT>%s<\n",temp);
1378             }
1379 
1380 
1381             // Check for a custom path having been set
1382             // in the Send Message dialog.  If so, use
1383             // this for our outgoing path instead and
1384             // reset all of the queued message paths to
1385             // this station to this new path.
1386             //
1387             get_send_message_path(to_call,
1388                                   new_path,
1389                                   sizeof(new_path));
1390 
1391 //fprintf(stderr,"get_send_message_path(%s) returned: %s\n",to_call,new_path);
1392 
1393             if (new_path[0] != '\0'
1394                 && strcmp(new_path,message_pool[i].path) != 0)
1395             {
1396 
1397               // We have a custom path set which is
1398               // different than the path saved with
1399               // the outgoing message.
1400               //
1401               // Change all messages to that callsign
1402               // to match the new path.
1403               //
1404               change_path_outgoing_messages_to(to_call,new_path);
1405             }
1406 
1407 
1408             // Transmit the message
1409             transmit_message_data(message_pool[i].to_call_sign,
1410                                   temp,
1411                                   message_pool[i].path);
1412 
1413 
1414             message_pool[i].active_time = time + message_pool[i].next_time;
1415 
1416             //fprintf(stderr,"%d\n",(int)message_pool[i].next_time);
1417           }
1418 
1419           /*
1420           fprintf(stderr,
1421               "Msg Interval = %3ld seconds or %4.1f minutes\n",
1422               message_pool[i].next_time,
1423               message_pool[i].next_time / 60.0);
1424           */
1425 
1426           // Record the interval we're using.  Put it with
1427           // the message in the general message pool, so
1428           // that the Send Message dialog can display it.
1429           // It will only display it if the message is
1430           // actively being transmitted.  If it has been
1431           // cancelled, timed out, or hasn't made it to
1432           // the transmit position yet, it won't be shown.
1433           //
1434           msg_record_interval_tries(message_pool[i].to_call_sign,
1435                                     message_pool[i].from_call_sign,
1436                                     message_pool[i].seq,
1437                                     message_pool[i].next_time,  // Interval
1438                                     message_pool[i].tries);     // Tries
1439 
1440           // Start at 7 seconds for the interval.  We set
1441           // it to 7 seconds in output_message() above.
1442           // Double the interval each retry until we hit
1443           // 10 minutes.  Keep transmitting at 10 minute
1444           // intervals until we hit MAX_TRIES.
1445 
1446           // Double the interval between messages
1447           message_pool[i].next_time = message_pool[i].next_time * 2;
1448 
1449           // Limit the max interval to 10 minutes
1450           if (message_pool[i].next_time > (time_t)600L)
1451           {
1452             message_pool[i].next_time = (time_t)600L;
1453           }
1454 
1455           message_pool[i].tries++;
1456 
1457           // Expire it if we hit the limit
1458           if (message_pool[i].tries > MAX_TRIES)
1459           {
1460             char temp[150];
1461             char temp_to[20];
1462 
1463             xastir_snprintf(temp,sizeof(temp),"To: %s, Msg: %s",
1464                             message_pool[i].to_call_sign,
1465                             message_pool[i].message_line);
1466             //popup_message(langcode("POPEM00004"),langcode("POPEM00017"));
1467             popup_message( "Retries Exceeded!", temp );
1468 
1469             // Fake the system out: We're pretending
1470             // that we got an ACK back from it so that
1471             // we can either release the next message to
1472             // go out, or at least make the send button
1473             // sensitive again.
1474             // We need to copy the to_call_sign into
1475             // another variable because the
1476             // clear_acked_message() function clears out
1477             // the message then needs this parameter to
1478             // do another compare (to enable the Send Msg
1479             // button again).
1480             xastir_snprintf(temp_to,
1481                             sizeof(temp_to),
1482                             "%s",
1483                             message_pool[i].to_call_sign);
1484 
1485             // Record a fake ack and add "*TIMEOUT*" to
1486             // the message.  This will be displayed in
1487             // the Send Message dialog.
1488             msg_record_ack(temp_to,
1489                            message_pool[i].from_call_sign,
1490                            message_pool[i].seq,
1491                            1,  // "1" specifies a timeout
1492                            0); // Not a cancel
1493 
1494             clear_acked_message(temp_to,
1495                                 message_pool[i].from_call_sign,
1496                                 message_pool[i].seq);
1497 
1498 //                        if (mw[i].send_message_dialog!=NULL) /* clear submit */
1499 //                            XtSetSensitive(mw[i].button_ok,TRUE);
1500           }
1501         }
1502       }
1503       else
1504       {
1505         if (debug_level & 2)
1506         {
1507           fprintf(stderr,"Message #%s is waiting to have a previous one cleared\n",message_pool[i].seq);
1508         }
1509       }
1510     }
1511   }
1512 }
1513 
1514 
1515 
1516 
1517 
1518 // Function which marks a message as ack'ed in the transmit queue
1519 // and releases the next message to allow it to be transmitted.
1520 // Handles REPLY-ACK format or normal ACK format just fine.
1521 //
clear_acked_message(char * from,char * to,char * seq)1522 void clear_acked_message(char *from, char *to, char *seq)
1523 {
1524   int i,ii;
1525   int found;
1526   char lowest[3];
1527   char temp1[MAX_CALLSIGN+1];
1528   char *temp_ptr;
1529   char msg_id[5+1];
1530 
1531 
1532   // Copy seq into local variable
1533   xastir_snprintf(msg_id,
1534                   sizeof(msg_id),
1535                   "%s",
1536                   seq);
1537 
1538   // Check for REPLY-ACK protocol.  If found, terminate at the end
1539   // of the first ack.
1540   temp_ptr = strchr(msg_id, '}');
1541   if (temp_ptr)
1542   {
1543     *temp_ptr = '\0';
1544   }
1545 
1546   (void)remove_trailing_spaces(msg_id);  // This is IMPORTANT here!!!
1547 
1548   //lowest=100000;
1549   // Highest Base-90 2-char string
1550   xastir_snprintf(lowest,sizeof(lowest),"zz");
1551   found= -1;
1552   for (i=0; i<MAX_OUTGOING_MESSAGES; i++)
1553   {
1554     if (message_pool[i].active==MESSAGE_ACTIVE)
1555     {
1556 
1557       if (debug_level & 1)
1558         fprintf(stderr,
1559                 "TO <%s> <%s> from <%s> <%s> seq <%s> <%s>\n",
1560                 to,
1561                 message_pool[i].to_call_sign,
1562                 from,
1563                 message_pool[i].from_call_sign,
1564                 msg_id,
1565                 message_pool[i].seq);
1566 
1567       if (strcmp(message_pool[i].to_call_sign,from)==0)
1568       {
1569         if (debug_level & 1)
1570         {
1571           fprintf(stderr,"Matched message to_call_sign\n");
1572         }
1573         if (strcmp(message_pool[i].from_call_sign,to)==0)
1574         {
1575           if (debug_level & 1)
1576           {
1577             fprintf(stderr,"Matched message from_call_sign\n");
1578           }
1579           if (strcmp(message_pool[i].seq,msg_id)==0)
1580           {
1581             if (debug_level & 2)
1582             {
1583               fprintf(stderr,"Found and cleared\n");
1584             }
1585 
1586             clear_outgoing_message(i);
1587             // now find and release next message, look for the lowest sequence?
1588 // What about when the sequence rolls over?
1589             for (i=0; i<MAX_OUTGOING_MESSAGES; i++)
1590             {
1591               if (message_pool[i].active==MESSAGE_ACTIVE)
1592               {
1593                 if (strcmp(message_pool[i].to_call_sign,from)==0)
1594                 {
1595 // Need to change this to a string compare instead of an integer
1596 // compare.  We are using base-90 encoding now.
1597                   //if (atoi(message_pool[i].seq)<lowest) {
1598                   if (strncmp(message_pool[i].seq,lowest,2) < 0)
1599                   {
1600                     //lowest=atoi(message_pool[i].seq);
1601                     xastir_snprintf(lowest,
1602                                     sizeof(lowest),
1603                                     "%s",
1604                                     message_pool[i].seq);
1605                     found=i;
1606                   }
1607                 }
1608               }
1609             }
1610             // Release the next message in the queue for transmission
1611             if (found!= -1)
1612             {
1613               message_pool[found].wait_on_first_ack=0;
1614             }
1615             else
1616             {
1617               /* if no more clear the send button */
1618 
1619               begin_critical_section(&send_message_dialog_lock, "messages.c:clear_acked_message" );
1620 
1621               for (ii=0; ii<MAX_MESSAGE_WINDOWS; ii++)
1622               {
1623                 /* find station  */
1624                 if (mw[ii].send_message_dialog!=NULL)
1625                 {
1626 
1627                   temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data);
1628                   xastir_snprintf(temp1,
1629                                   sizeof(temp1),
1630                                   "%s",
1631                                   temp_ptr);
1632                   XtFree(temp_ptr);
1633 
1634                   (void)to_upper(temp1);
1635                   //fprintf(stderr,"%s\t%s\n",temp1,from);
1636 //                                    if (strcmp(temp1,from)==0) {
1637                   /*clear submit*/
1638 //                                        XtSetSensitive(mw[ii].button_ok,TRUE);
1639 //                                    }
1640                 }
1641               }
1642 
1643               end_critical_section(&send_message_dialog_lock, "messages.c:clear_acked_message" );
1644 
1645             }
1646           }
1647           else
1648           {
1649             if (debug_level & 1)
1650             {
1651               fprintf(stderr,"Sequences didn't match: %s %s\n",message_pool[i].seq,msg_id);
1652             }
1653           }
1654         }
1655       }
1656     }
1657   }
1658 }
1659 
1660 
1661 
1662 
1663 
1664 // This routine is not currently used.
1665 //
send_queued(char * to)1666 void send_queued(char *to)
1667 {
1668   int i;
1669 
1670   for (i=0; i<MAX_OUTGOING_MESSAGES ; i++)
1671   {
1672     /* Check for messages to call */
1673     if (message_pool[i].active==MESSAGE_ACTIVE)
1674       if (strcmp(to,message_pool[i].to_call_sign)==0)
1675       {
1676         message_pool[i].active_time=0;
1677       }
1678 
1679   }
1680 }
1681 
1682