1 /* CWirc - X-Chat plugin for sending and receiving raw morse code over IRC
2    (c) Pierre-Philippe Coupard - 18/06/2003
3 
4    CW frames encoding/decoding routines
5 
6    This program is distributed under the terms of the GNU General Public License
7    See the COPYING file for details
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 
14 #include "types.h"
15 #include "cwframe.h"
16 #include "cwirc.h"
17 #include "grid.h"
18 #include "propagation.h"
19 #include "io.h"
20 #include "ipc.h"
21 
22 
23 
24 /* Prototypes */
25 static void rot46_enc_dec(char *msg);
26 static int decoded_number_basefmt(char **buf);
27 static int decoded_number_xfmt(char **buf);
28 static char *encoded_number_basefmt(int number);
29 static char *encoded_number_xfmt(int number);
30 
31 
32 
33 /* Encode a cw frame. A frame has the following format :
34 
35 [de=<encrypted callsign>,][at=<encrypted grid square,]<cw=|cx=><channel>
36 	<delay in ms><delay in ms><delay in ms> ...
37 
38 - The channel is a positive integer. I suggest using 1000 a general CQ channel.
39 
40 - Each delay is a positive or negative number. If it's positive, the sender's
41   key is down (beeping). If it's negative, the key is up (silence). The absolute
42   value of the number is the number of ms the event lasts
43 
44 The channel is always encoded in base format (2-letter block of printable
45 characters, see below). If the format is the base format ("cw=" header),
46 subsequent event delay values are also encoded in base format. If the format is
47 the extended format ("cx=" header), subsequent event delay values are encoded
48 in extended format (1- or 3-letter blocks of printable characters, see below).
49 
50   Return value : NULL --> the frame wasn't encoded
51                  pointer to the encoded frame
52 */
cwirc_encode_cw_frame(void)53 char *cwirc_encode_cw_frame(void)
54 {
55   static char cwframe[3+MAX_NICK_SIZE+1+3+MAX_GRIDSQUARE_SIZE+1+3+2+
56 			XMIT_BUF_MAX_SIZE*3+1];
57   char encoded_callsign[MAX_NICK_SIZE];
58   char encoded_gridsquare[MAX_GRIDSQUARE_SIZE];
59   T_BOOL send_callsign;
60   T_BOOL send_gridsquare;
61   char enc_evts_basefmt[XMIT_BUF_MAX_SIZE*2+1];
62   char enc_evts_xfmt[XMIT_BUF_MAX_SIZE*3+1];
63   T_U8 evts_fmt;	/* 0 -> evts in base fmt, 1 --> evts in extended fmt */
64   int i;
65 
66   if(!sharedmem->xmit_buf_flush_nb_evts)
67     return(NULL);
68 
69   send_callsign=sharedmem->send_callsign_with_cw && sharedmem->callsign[0];
70   send_gridsquare=sharedmem->send_gridsquare_with_cw &&sharedmem->gridsquare[0];
71 
72   if(send_callsign)
73   {
74     strcpy(encoded_callsign,sharedmem->callsign);
75     rot46_enc_dec(encoded_callsign);
76   }
77 
78   if(send_gridsquare)
79   {
80     strcpy(encoded_gridsquare,sharedmem->gridsquare);
81     rot46_enc_dec(encoded_gridsquare);
82   }
83 
84   /* Create a list of events encoded in base format */
85   enc_evts_basefmt[0]=0;
86   for(i=0;i<sharedmem->xmit_buf_flush_nb_evts;i++)
87     strcat(enc_evts_basefmt,encoded_number_basefmt(sharedmem->xmit_buf[i]));
88 
89   /* Create a list of events encoded in extended format */
90   enc_evts_xfmt[0]=0;
91   for(i=0;i<sharedmem->xmit_buf_flush_nb_evts;i++)
92     strcat(enc_evts_xfmt,encoded_number_xfmt(sharedmem->xmit_buf[i]));
93 
94   /* Use whatever format makes a shorter frame */
95   evts_fmt=(strlen(enc_evts_xfmt)<strlen(enc_evts_basefmt))?1:0;
96 
97   sprintf(cwframe,"%s%s%s%s%s%s%s%s%s",
98 		send_callsign?EXPLICIT_CALLSIGN_HEADER:"",
99 		send_callsign?encoded_callsign:"",
100 		send_callsign?",":"",
101 		send_gridsquare?GRID_SQUARE_HEADER:"",
102 		send_gridsquare?encoded_gridsquare:"",
103 		send_gridsquare?",":"",
104 		evts_fmt==0?CW_FRAME_HEADER_BASEFMT:CW_FRAME_HEADER_XFMT,
105 		encoded_number_basefmt(sharedmem->cwchannel[sharedmem->
106 			currcwchannel]),
107 		evts_fmt==0?enc_evts_basefmt:enc_evts_xfmt);
108 
109   return(cwframe);
110 }
111 
112 
113 
114 /* Decode a cw frame and insert it in the senders table. A frame has the
115 following format :
116 
117 [de=<encrypted callsign>,][at=<encrypted grid square,]<cw=|cx=><channel>
118 	<delay in ms><delay in ms><delay in ms> ...
119 
120 - The channel is a positive integer.
121 
122 - Each delay is a positive or negative number. If it's positive, the sender's
123   key is down (beeping). If it's negative, the key is up (silence). The absolute
124   value of the number is the number of ms the event lasts
125 
126 The channel is always encoded in base format (2-letter block of printable
127 characters, see below). If the format is the base format ("cw=" header),
128 subsequent event delay values are also encoded in base format. If the format is
129 the extended format ("cx=" header), subsequent event delay values are encoded
130 in extended format (1- or 3-letter blocks of printable characters, see below).
131 
132   Return value : 0 --> frame is cw frame, but not on our cw chan, or we drop it
133                  1 --> frame is a cw frame on our channel from a new sender,
134                        and is decoded
135                  2 --> frame is a cw frame on our channel from an already known
136                        sender and is decoded
137 
138   If a callsign was found in the frame, callsign points to it. Otherwise,
139   callsign is NULL.
140 */
cwirc_decode_cw_frame(char * sender_name,char * frame,char ** callsign)141 int cwirc_decode_cw_frame(char *sender_name,char *frame,char **callsign)
142 {
143   static char decoded_callsign[MAX_NICK_SIZE];
144   static char decoded_gridsquare[MAX_GRIDSQUARE_SIZE];
145   int distance_from_receiver;		/* In Km */
146   int i,j;
147   char *ptr,*ptr2;
148   int new_sender;
149   T_U8 evts_fmt;	/* 0 -> evts in base fmt, 1 --> evts in extended fmt */
150 
151   new_sender=0;
152   ptr=frame;
153 
154   /* Does the message start with the explicit callsign header ? */
155   *callsign=NULL;
156   if(!strncmp(ptr,EXPLICIT_CALLSIGN_HEADER,strlen(EXPLICIT_CALLSIGN_HEADER)))
157   {
158     /* Extract and decrypt the callsign */
159     ptr+=strlen(EXPLICIT_CALLSIGN_HEADER);
160     ptr2=strchr(ptr,',');
161     i=ptr2-ptr;
162     i=i>=MAX_NICK_SIZE?MAX_NICK_SIZE-1:i;
163     strncpy(decoded_callsign,ptr,i);
164     decoded_callsign[i]=0;
165     rot46_enc_dec(decoded_callsign);
166     if(decoded_callsign[0])
167     {
168       *callsign=decoded_callsign;
169       sender_name=decoded_callsign;
170     }
171     ptr=ptr2+1;
172   }
173 
174   /* Is there a grid square header next ? */
175   decoded_gridsquare[0]=0;
176   if(!strncmp(ptr,GRID_SQUARE_HEADER,strlen(GRID_SQUARE_HEADER)))
177   {
178     /* Extract and decrypt the grid square */
179     ptr+=strlen(GRID_SQUARE_HEADER);
180     ptr2=strchr(ptr,',');
181     i=ptr2-ptr;
182     i=i>=MAX_GRIDSQUARE_SIZE?MAX_GRIDSQUARE_SIZE-1:i;
183     strncpy(decoded_gridsquare,ptr,i);
184     decoded_gridsquare[i]=0;
185     rot46_enc_dec(decoded_gridsquare);
186     ptr=ptr2+1;
187   }
188 
189   /* Are events in extended format ?*/
190   if(ptr[1]=='w')
191   {
192     evts_fmt=0;
193     ptr+=strlen(CW_FRAME_HEADER_BASEFMT);
194   }
195   else
196   {
197     evts_fmt=1;
198     ptr+=strlen(CW_FRAME_HEADER_XFMT);
199   }
200 
201   /* Is the sender on our channel ? */
202   if(decoded_number_basefmt(&ptr)!=sharedmem->cwchannel[sharedmem->
203 	currcwchannel])
204     return(0);	/* Not our channel : ignore the frame */
205 
206   /* Acquire the semaphore */
207   if(!cwirc_sem_P(sharedmem->semid,SEM_ST))
208   {
209     /* Check if we already know the sender */
210     for(i=0;i<MAX_SENDERS && strcmp(sender_name,sharedmem->sender[i].name);i++);
211 
212     /* If the sender isn't known, or is known but is currently being timed out
213        for removal, treat it as a new sender */
214     if(i==MAX_SENDERS || (sharedmem->sender[i].playback_stop_timeout>0 &&
215 			sharedmem->sender[i].playback_start_timeout<=0))
216     {
217       new_sender=1;
218 
219       /* Find a free slot if the sender is new */
220       if(i==MAX_SENDERS)
221       {
222         for(i=0;i<MAX_SENDERS && sharedmem->sender[i].name[0];i++);
223 
224         if(i==MAX_SENDERS)	/* No free slot : */
225           return(0);	/* just drop the frame */
226 
227         sharedmem->sender[i].playback_stop_timeout=0;
228       }
229 
230       /* Initialize the slot for the sender */
231       for(j=0;j<MAX_EVT_BUFFER;j++)
232       {
233         sharedmem->sender[i].kcdelay[j]=0;
234         sharedmem->sender[i].keystate[j]=0;
235       }
236       sharedmem->sender[i].buf_head=0;
237       sharedmem->sender[i].keyup_tickcnt=0;
238       sharedmem->sender[i].keydown_tickcnt=0;
239       sharedmem->sender[i].keystate_prev=0;
240       strncpy(sharedmem->sender[i].name,sender_name,MAX_NICK_SIZE);
241       sharedmem->sender[i].name[MAX_NICK_SIZE-1]=0;
242 
243       /* Give sender a chance to send more events before our buffer underruns */
244       sharedmem->sender[i].playback_start_timeout=sharedmem->recv_buffering;
245     }
246 
247     /* Append the frame events to the sender's ring buffer */
248     j=sharedmem->sender[i].buf_head;
249     do
250     {
251       if(sharedmem->sender[i].kcdelay[j]<=0)
252       {
253         sharedmem->sender[i].kcdelay[j]=evts_fmt==0?
254 		decoded_number_basefmt(&ptr):decoded_number_xfmt(&ptr);
255         if(sharedmem->sender[i].kcdelay[j]>0)
256           sharedmem->sender[i].keystate[j]=1;
257         else
258         {
259           sharedmem->sender[i].keystate[j]=0;
260           sharedmem->sender[i].kcdelay[j]=-sharedmem->sender[i].kcdelay[j];
261         }
262       }
263 
264       if((++j)==MAX_EVT_BUFFER)
265         j=0;
266     }
267     while(j!=sharedmem->sender[i].buf_head && ptr[0]);
268 
269     /* If the sender has sent a grid square and ours is defined too, calculate
270        how far the sender is from us and make up a signal strength*/
271     if(sharedmem->gridsquare[0] && decoded_gridsquare[0])
272     {
273       distance_from_receiver=cwirc_great_circle_path(
274 				sharedmem->gridsquare,decoded_gridsquare);
275       sharedmem->sender[i].signal_strength=cwirc_determine_signal_strength(
276       				distance_from_receiver);
277     }
278     else
279       sharedmem->sender[i].signal_strength=-1;
280 
281     /* Release the semaphore */
282     cwirc_sem_V(sharedmem->semid,SEM_ST);
283   }
284 
285   return(new_sender?1:2);
286 }
287 
288 
289 
290 /* Check that a string looks like a valid cw frame */
cwirc_is_cw_frame(char * frame)291 int cwirc_is_cw_frame(char *frame)
292 {
293   char *ptr,*ptr2;
294   char buf[7];
295   T_U8 evts_fmt;	/* 0 -> evts in base fmt, 1 --> evts in extended fmt */
296   int i,j,k;
297 
298   ptr=frame;
299 
300   /* Is there an explicit header ? */
301   if(!strncmp(ptr,EXPLICIT_CALLSIGN_HEADER,strlen(EXPLICIT_CALLSIGN_HEADER)))
302   {
303     /* Yes: can we find a ',' after the header ? */
304     if((ptr=strchr(ptr,','))==NULL)
305       return(0);	/* No ','. Drop the frame */
306     else
307       ptr++;
308   }
309 
310   /* Is there a grid square header ? */
311   if(!strncmp(ptr,GRID_SQUARE_HEADER,strlen(GRID_SQUARE_HEADER)))
312   {
313     /* Yes: can we find a ',' after the header ? */
314     if((ptr2=strchr(ptr,','))==NULL)
315       return(0);	/* No ','. Drop the frame */
316     else
317     {
318       ptr+=strlen(GRID_SQUARE_HEADER);
319 
320       /* Check that the grid square is 4 or 6 characters long */
321       if(ptr2-ptr!=4 && ptr2-ptr!=6)
322         /* Invalid grid square. Drop the frame */
323         return(0);
324 
325       /* Check that the grid square is valid */
326       strncpy(buf,ptr,ptr2-ptr);
327       buf[ptr2-ptr]=0;
328       rot46_enc_dec(buf);
329       if(!cwirc_is_grid_square(buf))
330         /* Invalid grid square. Drop the frame */
331         return(0);
332 
333       ptr=ptr2+1;
334     }
335   }
336 
337   /* Is there a morse frame header ? */
338   if(strncmp(ptr,CW_FRAME_HEADER_BASEFMT,strlen(CW_FRAME_HEADER_BASEFMT)) &&
339 	strncmp(ptr,CW_FRAME_HEADER_XFMT,strlen(CW_FRAME_HEADER_XFMT)))
340     return(0);	/* Header not found. Drop the frame */
341 
342   /* Are events in extended format ?*/
343   if(ptr[1]=='w')
344   {
345     evts_fmt=0;
346     ptr+=strlen(CW_FRAME_HEADER_BASEFMT);
347 
348     /* Are there are least 4 chars (channel number+one delay) and is
349        the number of chars a multiple of 2 after the morse header ? */
350     if(strlen(ptr)<4 || strlen(ptr)%2)
351       return(0);	/* Not a valid frame length. Drop the frame */
352   }
353   else
354   {
355     evts_fmt=1;
356     ptr+=strlen(CW_FRAME_HEADER_XFMT);
357 
358     /* Are there are least 3 chars (channel number+one delay) ? */
359     if(strlen(ptr)<3)
360       return(0);	/* Not a valid frame length. Drop the frame */
361   }
362 
363   /* Are the characters only composed of printable characters between '!' (33)
364      and '~' (126) included ? */
365   for(i=0;i<strlen(ptr);i++)
366     if(ptr[i]<'!' || ptr[i]>'~')
367       return(0);/* Impossible character in an encoded delay. Drop the frame */
368 
369   /* Check that all the delays following the channel number have reasonable
370      values individually, i.e. less than 1.5x our own xmit delay and not null,
371      and the sum of all delays is less than 1.5x our own xmit delay.*/
372   ptr+=2;
373   k=0;
374   while(k<XMIT_BUF_DELAY*1.5 && ptr[0])
375   {
376     j=evts_fmt==0?decoded_number_basefmt(&ptr):decoded_number_xfmt(&ptr);
377     if(!j || (j<0?-j:j)>=XMIT_BUF_DELAY*1.5)
378       return(0);	/* Suspicious delay. Drop the frame */
379     k+=j<0?-j:j;
380   }
381   if(k>=XMIT_BUF_DELAY*1.5)
382     return(0);		/* Suspicious sum of delays. Drop the frame */
383 
384   return(1);
385 }
386 
387 
388 
389 /* Encrypt/decrypt a string with ROT46, using printable characters between
390    '!' (33) and '}' (125) included, but excluding ','. Any character outside
391    this set is silently discarded. This isn't much of an encryption, but it's
392    good enough to scramble things so they're not too easily readable. */
rot46_enc_dec(char * msg)393 static void rot46_enc_dec(char *msg)
394 {
395   int i,j,k;
396   unsigned char c;
397 
398   k=strlen(msg);
399 
400   /* Remove unwanted characters from the string */
401   i=0;
402   while(i<k)
403   {
404     if(msg[i]<'!' || msg[i]==',' || msg[i]>'}')
405     {
406       for(j=i;j<k;j++)
407         msg[j]=msg[j+1];
408       k--;
409     }
410     else
411       i++;
412   }
413 
414   /* ROT46 "encrypt"/"decrypt" the string */
415   for(i=0;i<k;i++)
416   {
417     c=(msg[i]>=','?msg[i]-1:msg[i])+46;
418     if(c>'}'-1)
419       c='!'+c-'}';
420     msg[i]=c>=','?c+1:c;
421   }
422 }
423 
424 
425 
426 /* Decode a signed number encoded into a string of 2 characters composed only of
427    printable characters between '!' (33) and '~' (126) included, and do so in an
428    endian-independant fashion.
429 
430    If an invalid character (including the string terminator) is encountered in
431    the 2 characters needed, the function returns -32768 and *buf points to the
432    offending character. If the call is successful, *buf points to the next
433    character after the encoded number. */
decoded_number_basefmt(char ** buf)434 static int decoded_number_basefmt(char **buf)
435 {
436   unsigned char c1,c2;
437 
438   c1=(*buf)[0];
439   if(c1<'!' || c1>'~')
440     return(-32768);
441   (*buf)++;
442 
443   c2=(*buf)[0];
444   if(c2<'!' || c2>'~')
445     return(-32768);
446   (*buf)++;
447 
448   return(((c1-'!')*94 + (c2-'!'))-4418);
449 }
450 
451 
452 
453 /* Decode a signed number encoded into a string of 1 or 3 characters composed
454    only of printable characters between '!' (33) and '~' (126) included, and do
455    so in an endian-independant fashion.
456 
457    The format is as follow:
458 
459    - If a character is between '!' and '~' excluded, it directly encodes the
460      number.
461 
462    - If a character is '~', the 2 characters that follow encode the number in
463      base format fashion (see above).
464 
465    If an invalid character (including the string terminator) is encountered in
466    the 1 or 3 characters needed, or if the format is invalid, the function
467    returns -32768 and *buf points to the offending character. If the call is
468    successful, *buf points to the next character after the encoded number. */
decoded_number_xfmt(char ** buf)469 static int decoded_number_xfmt(char **buf)
470 {
471   unsigned char c1;
472 
473   c1=(*buf)[0];
474   if(c1<'!' || c1>'~')
475     return(-32768);
476   (*buf)++;
477 
478   return(c1=='~'?decoded_number_basefmt(buf):(c1-'!')-46);
479 }
480 
481 
482 
483 /* Encode a signed number into a string of 2 characters composed only of
484    printable characters between '!' (33) and '~' (126) included, and do so in an
485    endian-independant fashion */
encoded_number_basefmt(int number)486 static char *encoded_number_basefmt(int number)
487 {
488   static char buf[3]={0,0,0};
489 
490   if(number<-4418) number=-4418;
491   if(number>4417) number=4417;
492   number+=4418;
493 
494   buf[0]='!'+number/94;
495   buf[1]='!'+number%94;
496 
497   return(buf);
498 }
499 
500 
501 
502 /* Encode a signed number into a string of 1, 2 or 3 characters composed only of
503    printable characters between '!' (33) and '~' (126) included, and do so in an
504    endian-independant fashion.
505 
506    The format is as follow:
507 
508    - If a number is between -46 and 46 included, it encodes into a single
509      characters.
510 
511    - If a number is between -92 and -47 included, or between 47 and 92 included,
512      it is encoded into 2 characters, which, decoded and summed up, reconstitute
513      the number.
514 
515    - If a number is less than -92 or greater than 92, it is encoded into 3
516      characters, the first one being '~' and the 2 others being the number
517      encoded in base format (see above).
518 */
encoded_number_xfmt(int number)519 static char *encoded_number_xfmt(int number)
520 {
521   static char buf[4];
522 
523   if(number>=-46 && number<=46)
524   {
525     buf[0]='!'+number+46;
526     buf[1]=0;
527     return(buf);
528   }
529 
530   if(number>=-92 && number<=92)
531   {
532     buf[0]=number<0?'!':'}';
533     buf[1]='!'+(number<0?number+92:number);
534     buf[2]=0;
535     return(buf);
536   }
537 
538   buf[0]='~';
539   strcpy(buf+1,encoded_number_basefmt(number));
540   return(buf);
541 }
542