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