/* * Linux Ax25 Console Client * von Manfred, DB3HM * * Kompilieren: * cc -o lacc -lax25 -lreadline lacc.c * (readline-Header-Dateien müssen installiert sein, desweiteren OpenSSL) * * Hinweis: * Dieses Programm wird als Technologie-Demo zur Verfügung gestellt. Es wird * keine Garantie für das Funktionieren übernommen und keine Haftung * für Folgen der Benutzung übernommen! * * Entstehunsgeschichte: * Dieses Programm ist aus einem kleinen Programmierbeispiel entstanden, * wurde sukzessive erweitert und ist zu einem einfachen, noch unvollständigen * und evtl. auch an einigen Stellen fehlerhaften AX.25 Client herangewachsen. * Das Programm ist jedenfalls ausreichend dafür, daß ich damit arbeite... * Mitarbeit an dem Programm ist gerne willkommen! * * Das Programm arbeitet mit dem Kernel-AX.25 von Linux. */ #define LACC_VERSION "0.18" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include char readline_input [256] ; int line_ready ; time_t start_time ; char remote_node [256] ; char caller [256] ; int rt_counter ; int rt_sum ; int mail_status ; FILE *mail_pipe ; char old_prompt [256] ; void process_line ( char *line ) ; int main ( int argc , char **argv ) { int this_socket ; int numbytes ; char buffer [256] ; fd_set readfds ; char command [256] ; char password [256] ; char response [256] ; int offset ; int counter ; char challenge [256] ; char openssl_command [256] ; FILE *this_pipe ; char md5_value [256] ; char to [256] ; char subject [256] ; char mail_command [256] ; int callsignsize ; char callsign [256] ; char hello_message [256] ; char beep [256] ; char prompt [256] ; char *hyphen_position ; char bye [256] ; char lang [10] ; char hello [10] ; char line_buffer [256] ; int rt_do ; time_t rt_start ; time_t rt_end ; char *bin_command ; char *hash_search ; char big_buffer [512] ; int extrabytes ; int hash_counter ; char upload_filename [256] ; FILE *upload_file ; char upload_line [256] ; char upload_buffer [256] ; /* announcment */ printf ( "LACC - Linux Ax.25 Console Client V%s by Manfred, DB3HM\n\n" , LACC_VERSION ) ; /* initialisierungen */ mail_status = 0 ; rt_counter = 0 ; rt_sum = 0 ; rt_do = 0 ; /* usage */ if ( argc == 1 ) { printf ( "usage examples:\n\n" ) ; printf ( "%s db0lj-8 : AX.25 connection\n" , argv [0] ) ; printf ( "%s db0lj-8 db0rpl : same over digi\n" , argv [0] ) ; printf ( "%s ui cq : AX.25 UI \"connection\"\n" , argv [0] ) ; printf ( "%s db0lj.dyndns.org 10023 : IP connection\n" , argv [0] ) ; printf ( "%s listen : incoming connection\n" , argv [0] ) ; printf ( "%s : this message\n" , argv [0] ) ; exit ( 0 ) ; } /* connect */ if ( strstr ( argv [1] , "." ) == NULL ) { /* AX.25 */ if ( strcmp ( argv [1] , "listen" ) == 0 ) printf ( "AX.25 listening for incoming calls...\n" ) ; else { if ( strcmp ( argv [1] , "ui" ) == 0 ) printf ( "AX25 UI \"connect\" to %s...\n" , argv [2] ) ; else printf ( "AX.25 connect to %s...\n" , argv [1] ) ; } this_socket = ax25_connect ( argv ) ; } else { /* TCP */ printf ( "TCP connect to %s...\n" , argv [1] ) ; this_socket = tcp_connect ( argv [1] , argv [2] ) ; } /* startzeitpunkt und Knoten merken */ time ( &start_time ) ; if ( strcmp ( argv [1] , "ui" ) != 0 ) strcpy ( remote_node , argv [1] ) ; else sprintf ( remote_node , "%s (UI)" , argv [2] ) ; /* readline initialisieren */ rl_bind_key ( '\t' , rl_insert ) ; rl_callback_handler_install ( "" , process_line ) ; /* Terminal-Emulation */ while ( 1 ) { FD_ZERO ( &readfds ) ; FD_SET ( STDIN_FILENO , &readfds ) ; FD_SET ( this_socket , &readfds ) ; select ( this_socket + 1 , &readfds , NULL , NULL , NULL ) ; if ( FD_ISSET ( STDIN_FILENO , &readfds ) ) { line_ready = 0 ; rl_callback_read_char () ; /* behandeln nur, wenn zeile fertig ist */ if ( line_ready == 1 ) { /* umkopieren, lf anhängen, länge ermitteln */ strcpy ( buffer , readline_input ) ; strcat ( buffer , "\r" ) ; numbytes = strlen ( buffer ) ; /* printf ( "%s\n" , buffer ) ; */ /* erst sonderfälle behandeln */ if ( strncmp ( buffer , "md5" , 3 ) == 0 ) { /* infos erfragen */ /* ### return values! */ rl_callback_handler_install ( "Command: " , process_line ) ; do { line_ready = 0 ; rl_callback_read_char () ; } while ( line_ready == 0 ) ; strcpy ( command , readline_input ) ; strcat ( command , "\r" ) ; rl_callback_handler_install ( "Password: " , process_line ) ; /* if ( isatty ( STDIN_FILENO ) ) system ( "/bin/stty -echo" ) ; */ do { line_ready = 0 ; rl_callback_read_char () ; } while ( line_ready == 0 ) ; strcpy ( password , readline_input ) ; /* if ( isatty ( STDIN_FILENO ) ) system ( "/bin/stty echo" ) ; */ write ( STDOUT_FILENO , "\n" , 1 ) ; /* authentifikation starten */ write ( STDOUT_FILENO , command , strlen ( command ) ) ; if ( mail_status == 1 ) fwrite ( command , 1 , strlen ( command ) , mail_pipe ) ; lf2cr ( command , strlen ( command ) ) ; write ( this_socket , command , strlen ( command ) ) ; /* challenge lesen */ read ( this_socket , response , sizeof ( response ) ) ; write ( STDOUT_FILENO , response , strlen ( response ) ) ; write ( STDOUT_FILENO , "\n" , 1 ) ; if ( mail_status == 1 ) { fwrite ( response , 1 , strlen ( response ) , mail_pipe ) ; fwrite ( "\n" , 1 , 1 , mail_pipe ) ; } offset = strstr ( response , "[" ) - response + 1 ; counter = 0 ; while ( isalnum ( response [offset+counter] ) ) { challenge [counter] = response [offset+counter] ; counter ++ ; } challenge [counter] = '\0' ; /* md5 wert berechnen */ sprintf ( openssl_command , "printf %s%s | /usr/bin/openssl md5" , challenge , password ) ; /* printf ( "%s" , openssl_command ) ; */ this_pipe = popen ( openssl_command , "r" ) ; fgets ( md5_value , sizeof ( md5_value ) , this_pipe ) ; pclose ( this_pipe ) ; /* senden */ write ( STDOUT_FILENO , md5_value , strlen ( md5_value ) ) ; if ( mail_status == 1 ) fwrite ( md5_value , 1 , strlen ( md5_value ) , mail_pipe ) ; lf2cr ( md5_value , strlen ( md5_value ) ) ; write ( this_socket , md5_value , strlen ( md5_value ) ) ; } else if ( strncmp ( buffer , "ctrl" , 4 ) == 0 ) { /* ctrl-sequence senden */ buffer [0] = buffer [4] - 'a' + 1 ; buffer [1] = '\r' ; write ( this_socket , buffer , 2 ) ; /* prompt restoren */ rl_callback_handler_install ( old_prompt , process_line ) ; } else if ( strncmp ( buffer , "mailbegin" , 9 ) == 0 ) { if ( mail_status == 0 ) { mail_status = 1 ; /* infos erfragen */ rl_callback_handler_install ( "To: " , process_line ) ; do { line_ready = 0 ; rl_callback_read_char () ; } while ( line_ready == 0 ) ; strcpy ( to , readline_input ) ; rl_callback_handler_install ( "Subject: " , process_line ) ; do { line_ready = 0 ; rl_callback_read_char () ; } while ( line_ready == 0 ) ; strcpy ( subject , readline_input ) ; sprintf ( mail_command , "mail %s -s \"%s\"" , to , subject ) ; /* mail beginnen */ mail_pipe = popen ( mail_command , "w" ) ; } else { /* unlogisch, fehlermeldung */ write ( STDOUT_FILENO , "mail already started!\n" , 22 ) ; } /* prompt restoren */ rl_callback_handler_install ( old_prompt , process_line ) ; } else if ( strncmp ( buffer , "mailend" , 7 ) == 0 ) { if ( mail_status == 1 ) { mail_status = 0 ; /* mail beenden */ pclose ( mail_pipe ) ; /* message! */ write ( STDOUT_FILENO , "mail sent!\n" , 11 ) ; } else { /* unlogisch, fehlermeldung */ write ( STDOUT_FILENO , "no mail started!\n" , 17 ) ; } /* prompt restoren */ rl_callback_handler_install ( old_prompt , process_line ) ; } else if ( strncmp ( buffer , "stat" , 4 ) == 0 ) { /* im mail anzeigen, das wir das tun */ if ( mail_status == 1 ) fwrite ( buffer , 1 , numbytes , mail_pipe ) ; /* statistik erzeugen */ statistic () ; /* prompt restoren */ rl_callback_handler_install ( old_prompt , process_line ) ; } else if ( strncmp ( buffer , "upload" , 6 ) == 0 ) { rl_callback_handler_install ( "Filename: " , process_line ) ; do { line_ready = 0 ; rl_callback_read_char () ; } while ( line_ready == 0 ) ; strcpy ( upload_filename , readline_input ) ; /* versuch, die datei zu öffnen */ upload_file = fopen ( upload_filename , "r" ) ; if ( upload_file == NULL ) { /* geht nicht, meldung ausgeben */ write ( STDOUT_FILENO , "File does not exist!\n" , 21 ) ; } else { /* buffer zunächst leer */ numbytes = 0 ; /* file bis eof lesen und schicken */ while ( fgets ( upload_line , sizeof ( upload_line ) , upload_file ) != NULL ) { /* würde buffer übervoll? */ if ( numbytes + strlen ( upload_line ) <= sizeof ( upload_buffer ) ) { /* nein: kopie in buffer */ memcpy ( upload_buffer + numbytes , upload_line , strlen ( upload_line ) ) ; /* offset inkrementieren */ numbytes += strlen ( upload_line ) ; } else { /* buffer ausgeben */ /* auf bildschirm */ write ( STDOUT_FILENO , upload_buffer , numbytes ) ; /* evtl. auch in mail */ if ( mail_status == 1 ) fwrite ( upload_buffer , 1 , numbytes , mail_pipe ) ; /* konvertieren */ lf2cr ( upload_buffer , numbytes ) ; /* senden */ write ( this_socket , upload_buffer , numbytes ) ; /* buffer neu aufbauen */ memcpy ( upload_buffer , upload_line , strlen ( upload_line ) ) ; numbytes = strlen ( upload_line ) ; } } /* rest buffer ausgeben */ /* auf bildschirm */ write ( STDOUT_FILENO , upload_buffer , numbytes ) ; /* evtl. auch in mail */ if ( mail_status == 1 ) fwrite ( upload_buffer , 1 , numbytes , mail_pipe ) ; /* konvertieren */ lf2cr ( upload_buffer , numbytes ) ; /* senden */ write ( this_socket , upload_buffer , numbytes ) ; } /* melden, dass übertragung fertig ist */ write ( STDOUT_FILENO , "File sent!\n" , 11 ) ; /* prompt restoren (wohl meist leer) */ rl_callback_handler_install ( old_prompt , process_line ) ; } else { /* allgemeiner fall */ /* falls nötig in mail schreiben */ if ( mail_status == 1 ) fwrite ( buffer , 1 , numbytes , mail_pipe ) ; /* konvertieren */ lf2cr ( buffer , numbytes ) ; /* zeitnahme für response time messung */ time ( &rt_start ) ; rt_do = 1 ; /* buffer senden */ write ( this_socket , buffer , numbytes ) ; } } } if ( FD_ISSET ( this_socket , &readfds ) ) { /* bytes von socket lesen */ numbytes = read ( this_socket , buffer , sizeof ( buffer ) ) ; /* response time messung */ if ( rt_do == 1 ) { time ( &rt_end ) ; rt_do = 0 ; rt_sum += ( (int) rt_end - (int) rt_start ) ; rt_counter ++ ; } /* abbruch bei disconnect durch remote */ if ( numbytes <= 0 ) { printf ( "peer disconnected us...\n" ) ; clean_exit () ; } /* sonderfall: bin format */ /* #BIN# wird noch nicht erkannt, wenn mitten durch diese 5 Zeichen die Paketgrenze geht. Gibt es hier einen guten Algorithmus? */ bin_command = strstr ( buffer , "#BIN#" ) ; if ( ( bin_command != NULL ) && ( ( (int) bin_command - (int) buffer ) < numbytes ) ) { /* wenn wir hinter dem bin nicht 5 # finden, liegt der string auf der paketgrenze. in dem falle laden wir noch ein paket dahinter... (seufz) */ hash_search = bin_command ; hash_counter = 0 ; while ( ( hash_counter < 5 ) && ( ( (int) hash_search - (int) buffer ) < numbytes ) ) { if ( *hash_search == '#' ) hash_counter ++ ; hash_search ++ ; } if ( hash_counter == 5 ) { /* download einfach aufrufen */ bin_download ( buffer , numbytes , bin_command , this_socket ) ; } else { /* ein cr am ende wollen wir nicht mitkopieren */ if ( buffer[numbytes-1] == '\r' ) numbytes -- ; /* buffer umkopieren */ memcpy ( big_buffer , buffer , numbytes ) ; /* nachladen */ extrabytes = read ( this_socket , big_buffer + numbytes , sizeof ( big_buffer ) - numbytes ) ; if ( extrabytes <= 0 ) { printf ( "peer disconnected us...\n" ) ; clean_exit () ; } /* im neuen buffer #BIN# suchen */ bin_command = strstr ( big_buffer , "#BIN#" ) ; /* und download starten */ bin_download ( big_buffer , numbytes + extrabytes , bin_command , this_socket ) ; } } else { /* konvertieren */ cr2lf ( buffer , numbytes ) ; /* falls nötig in mail schreiben */ if ( mail_status == 1 ) fwrite ( buffer , 1 , numbytes , mail_pipe ) ; write ( STDOUT_FILENO , buffer , numbytes ) ; /* sonderfall: exit bei listen */ if ( ( strcmp ( remote_node , "listen" ) == 0 ) && ( numbytes == 4 ) && ( strncmp ( buffer , "//q" , 3 ) == 0 ) ) { /* verabschieden */ strcpy ( callsign , caller ) ; hyphen_position = strstr ( callsign , "-" ) ; if ( hyphen_position != NULL ) *hyphen_position = '\0' ; sprintf ( bye , "Tschuess %s!\r" , callsign ) ; write ( this_socket , bye , strlen ( bye ) ) ; cr2lf ( bye , strlen ( bye ) ) ; write ( STDOUT_FILENO , bye , strlen ( bye ) ) ; clean_exit () ; } /* prompt setzen */ offset = numbytes - 1 ; while ( ( buffer [offset] != '\n' ) && ( offset >= 0 ) ) offset -- ; strncpy ( prompt , buffer + offset + 1 , numbytes - offset - 1 ) ; prompt [numbytes-offset-1] = '\0' ; /* sonderfall: prompt im vorherigen paket unvollständig */ if ( ( offset == -1 ) && ( strcmp ( rl_prompt , "\r" ) != 0 ) && ( strlen ( rl_prompt ) + numbytes <= sizeof ( prompt ) ) ) { strcpy ( prompt , rl_prompt ) ; strncat ( prompt , buffer , numbytes ) ; prompt[strlen(rl_prompt)+numbytes] = '\0' ; } write ( STDOUT_FILENO , "\r" , 1 ) ; strcpy ( line_buffer , rl_line_buffer ) ; if ( strlen ( prompt ) != 0 ) rl_callback_handler_install ( prompt , process_line ) ; else rl_callback_handler_install ( "\r" , process_line ) ; rl_insert_text ( line_buffer ) ; rl_refresh_line ( 0 , 0 ) ; /* sonderfall: convers-auto-begruessung */ if ( ( strncmp ( buffer , "***" , 3 ) == 0 ) && ( strstr ( buffer , " joined channel " ) != NULL ) && ( strstr ( buffer , ")" ) != NULL ) && ( strstr ( buffer , "@" ) != NULL ) ) { callsignsize = strstr ( buffer , "@" ) - strstr ( buffer , ")" ) - 2 ; if ( callsignsize <= 6 ) { strncpy ( callsign , strstr ( buffer , ")" ) + 2 , callsignsize ) ; callsign [callsignsize] = '\0' ; /* sprache unterscheiden */ language ( callsign , lang ) ; if ( strcmp ( lang , "de" ) == 0 ) strcpy ( hello , "Hallo" ) ; else strcpy ( hello , "Hello" ) ; sprintf ( hello_message , "%s %s!\r" , hello , callsign ) ; /* senden */ write ( this_socket , hello_message , strlen ( hello_message ) ) ; cr2lf ( hello_message , strlen ( hello_message ) ) ; write ( STDOUT_FILENO , hello_message , strlen ( hello_message ) ) ; if ( mail_status == 1 ) { fwrite ( hello_message , 1 , strlen ( hello_message ) , mail_pipe ) ; } /* alarm */ strcpy ( beep , "\007\007\007" ) ; write ( STDOUT_FILENO , beep , 3 ) ; } } } } } } int ax25_connect ( char **nodelist ) { char *addr ; int this_socket ; int addrlen = sizeof ( struct full_sockaddr_ax25 ) ; struct full_sockaddr_ax25 axbind ; struct full_sockaddr_ax25 axconnect ; int numbytes ; char mycall [15] ; char mycall_ssid [15] ; struct full_sockaddr_ax25 axaccept ; int addrlen_accept ; int new_socket ; char callsign [256] ; char *hyphen_position ; char greeting [256] ; char beep [256] ; int myssid ; int ssid ; int connect_status ; char port_call [15] ; char mycall_simple [15] ; char *call_hyphen ; /* Grundlegende Festlegungen */ axconnect.fsa_ax25.sax25_family = axbind.fsa_ax25.sax25_family = \ AF_AX25 ; axbind.fsa_ax25.sax25_ndigis = 1 ; /* Rufzeichen erfragen */ if ( getenv ( "mycall" ) != NULL ) { strcpy ( mycall , getenv ( "mycall" ) ) ; printf ( "mycall = %s\n" , mycall ) ; } else { printf ( "mycall: " ) ; fgets ( mycall , sizeof ( mycall ) , stdin ) ; mycall [strlen(mycall)-1] = '\0' ; printf ( "use 'export mycall=%s' to avoid this question!\n" , mycall ) ; } /* rufzeichen ohne ssid */ strcpy ( mycall_simple , mycall ) ; call_hyphen = strstr ( mycall_simple , "-" ) ; if ( call_hyphen != NULL ) *call_hyphen = '\0' ; /* ssid */ if ( ( getenv ( "myssid" ) != NULL ) && ( strlen ( getenv ( "myssid" ) ) > 0 ) && ( atoi ( getenv ( "myssid" ) ) >= 0 ) && ( atoi ( getenv ( "myssid" ) ) <= 15 ) ) { myssid = atoi ( getenv ( "myssid" ) ) ; printf ( "ssid set to %d from environment variable\n" , myssid ) ; } else { myssid = -1 ; } /* set mycall_ssid */ if ( myssid == -1 ) sprintf ( mycall_ssid , "%s-0" , mycall_simple ) ; else sprintf ( mycall_ssid , "%s-%d" , mycall_simple , myssid ) ; /* printf ( "%s %s\n" , mycall , mycall_ssid ) ; */ /* port festlegen */ if ( ( getenv ( "myport" ) != NULL ) && ( strlen ( getenv ( "myport" ) ) > 0 ) ) { if ( ax25_config_load_ports () == 0 ) { printf ( "ERROR: could not load axports file\n" ) ; exit ( -1 ) ; } if ( ax25_config_get_addr ( getenv ( "myport" ) ) == NULL ) { printf ( "ERROR: could not get port info for %s\n" , getenv ( "myport" ) ) ; exit ( -1 ) ; } printf ( "myport = %s\n" , getenv ( "myport" ) ) ; strcpy ( port_call , ax25_config_get_addr ( getenv ( "myport" ) ) ) ; printf ( "port callsign = %s\n" , port_call ) ; } else { /* wenn kein Port festgelegt ist, nehmen wir einfach das mycall */ strcpy ( port_call , mycall ) ; } /* Rufzeichen festlegen */ if ( ax25_aton_entry ( port_call , axbind.fsa_digipeater[0].ax25_call ) == -1 ) { printf ( "ERROR: invalid AX.25 port callsign - %s\n" , port_call ) ; exit ( -1 ) ; } /* SSID festlegen */ if ( ax25_aton_entry ( mycall_ssid , axbind.fsa_ax25.sax25_call.ax25_call ) == -1 ) { printf ( "ERROR: invalid callsign - %s\n" , mycall_ssid ) ; exit ( -1 ) ; } /* Socket holen */ if ( strcmp ( nodelist [1] , "ui" ) == 0 ) { /* Sonderfall: UI-Connect */ if ( ( this_socket = socket ( AF_AX25 , SOCK_DGRAM , 0 ) ) < 0 ) { printf ( "ERROR: cannot open AX.25 UI socket, %s\n" , strerror ( errno ) ) ; exit ( -1 ) ; } /* Ziel festlegen */ if ( ax25_aton_arglist ( nodelist+2 , &axconnect ) == -1 ) { printf ( "ERROR: invalid destination callsign or digipeater\n" ) ; exit ( -1 ) ; } } else { /* normaler Connect */ if ( ( this_socket = socket ( AF_AX25 , SOCK_SEQPACKET , 0 ) ) < 0 ) { printf ( "ERROR: cannot open AX.25 socket, %s\n" , strerror ( errno ) ) ; exit ( -1 ) ; } /* Ziel festlegen */ if ( ax25_aton_arglist ( nodelist+1 , &axconnect ) == -1 ) { printf ( "ERROR: invalid destination callsign or digipeater\n" ) ; exit ( -1 ) ; } } /* Bind auf eigenes Rufzeichen */ if ( bind ( this_socket , ( struct sockaddr *) &axbind , addrlen ) != 0 ) { printf ( "ERROR: cannot bind AX.25 socket, %s\n" , strerror ( errno ) ) ; printf ( "\nIMPORTANT HINT:\n" ) ; printf ( "either environment variable 'mycall' (optionally including the SSID)\n" ) ; printf ( "or 'myport' (if it exists) should match a line in your axports file!\n" ) ; exit ( -1 ) ; } /* ui listener ### */ /* funktioniert so noch nicht - funktioniert es überhaupt? */ if ( ( strcmp ( nodelist [1] , "ui" ) == 0 ) && ( strcmp ( nodelist [2] , "listen" ) == 0 ) ) return this_socket ; /* sonderfall: listener */ if ( strcmp ( nodelist [1] , "listen" ) == 0 ) { /* listener einrichten */ if ( listen ( this_socket , 1 ) < 0 ) { printf ( "ERROR: cannot listen to AX.25 socket, %s\n" , strerror ( errno ) ) ; exit ( -1 ) ; } /* auf connect warten */ addrlen_accept = addrlen ; new_socket = accept ( this_socket , (struct sockaddr *) &axaccept , &addrlen_accept ) ; if ( new_socket < 0 ) { printf ( "ERROR: cannot accept AX.25 socket, %s\n" , strerror ( errno ) ) ; exit ( -1 ) ; } /* infos und begruessung */ strcpy ( caller , (char *) ax25_ntoa ( &axaccept.fsa_ax25.sax25_call ) ) ; printf ( "Connect received from %s...\n" , caller ) ; strcpy ( callsign , caller ) ; hyphen_position = strstr ( callsign , "-" ) ; if ( hyphen_position != NULL ) *hyphen_position = '\0' ; sprintf ( greeting , "Hallo %s!\r" , callsign ) ; write ( new_socket , greeting , strlen ( greeting ) ) ; cr2lf ( greeting , strlen ( greeting ) ) ; write ( STDOUT_FILENO , greeting , strlen ( greeting ) ) ; sprintf ( greeting , "Dies ist die Packet-Radio-Station von %s" , mycall_simple ) ; if ( ( getenv ( "myqth" ) != NULL ) && ( strlen ( getenv ( "myqth" ) ) > 0 ) ) sprintf ( greeting , "%s in %s" , greeting, getenv ( "myqth" ) ) ; strcat ( greeting , ".\r" ) ; write ( new_socket , greeting , strlen ( greeting ) ) ; cr2lf ( greeting , strlen ( greeting ) ) ; write ( STDOUT_FILENO , greeting , strlen ( greeting ) ) ; strcpy ( beep , "\007\007\007" ) ; write ( STDOUT_FILENO , beep , 3 ) ; /* alten socket schließen */ close ( this_socket ) ; /* neuen (!) socket zurückgeben */ return new_socket ; } /* Verbindungsaufbau */ connect_status = connect ( this_socket , (struct sockaddr *) &axconnect , addrlen ) ; if ( connect_status != 0 ) { /* ssid inkrementieren, falls nötig */ if ( errno == EADDRINUSE ) { ssid = 0 ; if ( myssid != -1 ) { printf ( "ERROR: ssid in use, try to avoid setting myssid!\n" ) ; exit ( -1 ); } else { do { ssid ++ ; printf ( "now trying ssid %d...\n" , ssid ) ; sprintf ( mycall_ssid , "%s-%d" , mycall_simple , ssid ) ; /* neue SSID festlegen */ if ( ax25_aton_entry ( mycall_ssid , axbind.fsa_ax25.sax25_call.ax25_call ) == -1 ) { printf ( "ERROR: invalid callsign - %s\n" , mycall_ssid ) ; exit ( -1 ) ; } /* neuen socket holen */ close ( this_socket ) ; if ( ( this_socket = socket ( AF_AX25 , SOCK_SEQPACKET , 0 ) ) < 0 ) { printf ( "ERROR: cannot open AX.25 socket, %s\n" , strerror ( errno ) ) ; exit ( -1 ) ; } /* noch mal bind */ if ( bind ( this_socket , (struct sockaddr *) &axbind , addrlen ) != 0 ) { printf ( "ERROR: cannot bind AX.25 socket, %s\n" , strerror ( errno ) ) ; exit ( -1 ) ; } /* noch mal connect */ connect_status = connect ( this_socket , (struct sockaddr *) &axconnect , addrlen ) ; } while ( ( connect_status != 0 ) && ( errno == EADDRINUSE ) && ( ssid <= 15 ) ) ; } } /* sonstige Fehlerbehandlung */ if ( connect_status != 0 ) { printf ( "ERROR: cannot connect to AX.25 callsign, %s\n" , strerror ( errno ) ) ; exit ( -1 ) ; } } return this_socket ; } lf2cr ( char *buffer , int size ) { int counter ; for ( counter = 0 ; counter < size ; counter ++ ) if ( buffer [counter] == '\n' ) buffer [counter] = '\r' ; } cr2lf ( char *buffer , int size ) { int counter ; for ( counter = 0 ; counter < size ; counter ++ ) if ( buffer [counter] == '\r' ) buffer [counter] = '\n' ; } int tcp_connect ( char *node_name , char *service_name ) { struct servent *this_service ; int this_port ; struct hostent *this_host ; struct in_addr *this_internet_address ; int this_socket ; struct sockaddr_in this_socket_address ; int connected ; /* get service name */ this_service = getservbyname ( service_name , "tcp" ) ; if ( this_service != NULL ) { this_port = this_service->s_port ; } else { if ( ( atoi ( service_name ) > 0 ) && ( atoi ( service_name ) < 65536 ) ) { this_port = htons ( atoi ( service_name ) ) ; } else { printf ( "ERROR: service not found.\n" ) ; exit ( -1 ) ; } } /* get host name */ this_host = gethostbyname ( node_name ) ; if ( this_host == NULL ) { printf ( "ERROR: node not found.\n" ) ; exit ( -1 ) ; } this_internet_address = (struct in_addr* ) *this_host->h_addr_list ; /* open socket */ this_socket = socket ( AF_INET , SOCK_STREAM , 0 ) ; if ( this_socket < 0 ) { printf ( "ERROR: cannot open socket.\n" ) ; exit ( -1 ) ; } /* connect */ this_socket_address.sin_family = AF_INET ; this_socket_address.sin_port = this_port ; this_socket_address.sin_addr.s_addr = this_internet_address->s_addr ; connected = connect ( this_socket , (struct sockaddr *) &this_socket_address , sizeof ( this_socket_address ) ) ; /* error handling */ if ( connected < 0 ) { printf ( "ERROR: connect failed.\n" ) ; exit ( -1 ) ; } /* return file handle */ return this_socket ; } /* bin download durchführen */ bin_download ( char *last_buffer , int numbytes , char *bin_command , int this_socket ) { int total_bytes ; char filename [256] ; char local_filename [256] ; int local_file ; int bytes_loaded ; int next_bytes ; char buffer[256] ; int offset ; int hash_counter ; char progress [256] ; char *cr_search ; int bin_command_size ; int rest ; char *hash_search ; /* anfang des puffers konvertieren und ausgeben */ cr2lf ( last_buffer , (int) bin_command - (int) last_buffer ) ; write ( STDOUT_FILENO , last_buffer , (int) bin_command - (int) last_buffer ) ; /* syntax analysieren - haben wir jetzt endlich 5 Hashes? */ hash_search = bin_command ; hash_counter = 0 ; while ( ( hash_counter < 5 ) && ( ( (int) hash_search - (int) last_buffer ) < numbytes ) ) { if ( *hash_search == '#' ) hash_counter ++ ; hash_search ++ ; } /* wenn nicht, dann abbruch! */ if ( hash_counter != 5 ) { write ( STDOUT_FILENO , "Invalid #BIN# command:\n" , 23 ) ; write ( STDOUT_FILENO , bin_command , numbytes - ( (int) bin_command - (int) last_buffer ) ) ; write ( STDOUT_FILENO , "\n" , 1 ) ; return ; } /* suche nun ein cr, wenn es vorhanden ist, ist das das ende des bin kommandos, sonst das paket-ende tolererie auch lf statt cr! */ cr_search = hash_search ; while ( ( *cr_search != '\r' ) && ( *cr_search != '\n' ) && ( ( (int) cr_search - (int) last_buffer ) < numbytes ) ) cr_search ++ ; if ( ( *cr_search == '\r' ) || ( *cr_search == '\n' ) ) bin_command_size = (int) cr_search - (int) bin_command ; else bin_command_size = numbytes - ( (int) bin_command - (int) last_buffer ) ; /* kommando ausgeben */ write ( STDOUT_FILENO , bin_command , bin_command_size ) ; write ( STDOUT_FILENO , "\n" , 1 ) ; /* kommando analysieren */ offset = 0 ; hash_counter = 0 ; while ( ( offset < bin_command_size ) && ( hash_counter < 5 ) ) { if ( bin_command [offset] == '#' ) { hash_counter ++ ; switch ( hash_counter ) { case 2: total_bytes = atoi ( bin_command + offset + 1 ) ; break ; case 5: strncpy ( filename , bin_command + offset + 1 , bin_command_size - ( offset + 1 ) ) ; filename[bin_command_size-(offset+1)] = '\0' ; break ; } } offset ++ ; } if ( hash_counter != 5 ) { write ( STDOUT_FILENO , "Invalid #BIN# command!\n" , 23 ) ; return ; } /* checks filename */ for ( offset = 0 ; offset < strlen ( filename ) ; offset ++ ) if ( filename [offset] == '/' ) filename [offset] = '_' ; sprintf ( local_filename , "download_%s" , filename ) ; /* zieldatei öffnen */ local_file = open ( local_filename , O_WRONLY | O_CREAT , 0600 ) ; if ( local_file < 0 ) { write ( STDOUT_FILENO , "Can't store file!\n" , 18 ) ; return ; } /* OK senden (braucht nicht jede gegenstelle?) */ write ( this_socket , "#OK#\r" , 5 ) ; write ( STDOUT_FILENO , "#OK#\n" , 5 ) ; /* download durchführen */ bytes_loaded = 0 ; /* hing noch was im alten paket? */ rest = numbytes - ( (int) bin_command - (int) last_buffer ) - ( bin_command_size + 1 ) ; if ( rest > 0 ) { write ( local_file , bin_command + bin_command_size + 1 , rest ) ; bytes_loaded += rest ; sprintf ( progress , "%d of %d bytes loaded (%.2f%%)...\r" , bytes_loaded , total_bytes , 100.0 * (float) bytes_loaded / (float) total_bytes ) ; write ( STDOUT_FILENO , progress , strlen ( progress ) ) ; } /* schleife */ while ( bytes_loaded < total_bytes ) { next_bytes = read ( this_socket , buffer , sizeof ( buffer ) ) ; if ( next_bytes <= 0 ) { printf ( "peer disconnected us...\n" ) ; clean_exit () ; } bytes_loaded += next_bytes ; if ( bytes_loaded <= total_bytes ) { write ( local_file , buffer , next_bytes ) ; sprintf ( progress , "%d of %d bytes loaded (%.2f%%)...\r" , bytes_loaded , total_bytes , 100.0 * (float) bytes_loaded / (float) total_bytes ) ; write ( STDOUT_FILENO , progress , strlen ( progress ) ) ; if ( bytes_loaded == total_bytes ) write ( STDOUT_FILENO , "\nDownload finished!\n" , 20 ) ; } else { /* sonderfall: download zuende, aber es kommt noch was */ rest = total_bytes - ( bytes_loaded - next_bytes ) ; write ( local_file , buffer , rest ) ; sprintf ( progress , "%d of %d bytes loaded (%.2f%%)...\r" , total_bytes , total_bytes , 100.0 ) ; write ( STDOUT_FILENO , progress , strlen ( progress ) ) ; write ( STDOUT_FILENO , "\nDownload finished!\n" , 20 ) ; cr2lf ( buffer + rest , next_bytes - rest ) ; write ( STDOUT_FILENO , buffer + rest , next_bytes - rest ) ; } } /* fertig */ close ( local_file ) ; } /* eingabezeile von readline verwalten */ void process_line ( char *line ) { /* printf ( "%s\n" , line ) ; */ /* abbruch bei eof */ if ( line == NULL ) { printf ( "local eof found...\n" ) ; clean_exit () ; } /* umkopieren (achtung, buffer overflows) */ strncpy ( readline_input , line , sizeof (readline_input) - 2 ) ; readline_input [sizeof(readline_input)-2] = '\0' ; /* printf ( "%s\n" , readline_input ) ; */ /* flag setzen */ line_ready = 1 ; /* zur history hinzufügen (muss vor prompt rücksetzen stehen) */ add_history ( line ) ; /* alten prompt in bestimmten situationen sichern */ if ( ( strncmp ( line , "ctrl" , 4 ) == 0 ) || ( strncmp ( line , "mailbegin" , 9 ) == 0 ) || ( strncmp ( line , "mailend" , 7 ) == 0 ) || ( strncmp ( line , "stat" , 4 ) == 0 ) ) strcpy ( old_prompt , rl_prompt ) ; /* prompt zurücksetzen */ rl_callback_handler_install ( "\r" , process_line ) ; } /* sauberes programmende */ clean_exit () { FILE *logfile ; time_t end_time ; char start_time_string [256] ; char end_time_string [256] ; /* terminal-eigenschaften zurücksetzen */ rl_deprep_terminal () ; /* log schreiben */ time ( &end_time ) ; strcpy ( start_time_string , ctime ( &start_time ) ) ; start_time_string [strlen(start_time_string)-1] = '\0' ; strcpy ( end_time_string , ctime ( &end_time ) ) ; end_time_string [strlen(end_time_string)-1] = '\0' ; logfile = fopen ( "packet.log" , "a" ) ; if ( strcmp ( remote_node , "listen" ) != 0 ) { fprintf ( logfile , "%s - %s => %s\n" , start_time_string , end_time_string , remote_node ) ; } else { fprintf ( logfile , "%s - %s <= %s\n" , start_time_string , end_time_string , caller ) ; } fclose ( logfile ) ; /* statistik ausgeben */ statistic () ; /* beenden */ exit ( 0 ) ; } /* welche sprache entspricht dem rufzeichen? */ language ( char *callsign , char *lang ) { if ( ( toupper ( callsign [0] ) == 'D' ) && ( toupper ( callsign [1] ) >= 'A' ) && ( toupper ( callsign [1] ) <= 'R' ) ) strcpy ( lang , "de" ) ; else if ( ( toupper ( callsign [0] ) == 'O' ) && ( toupper ( callsign [1] ) == 'E' ) ) strcpy ( lang , "de" ) ; else if ( ( toupper ( callsign [0] ) == 'H' ) && ( toupper ( callsign [1] ) == 'B' ) ) strcpy ( lang , "de" ) ; else if ( ( toupper ( callsign [0] ) == 'L' ) && ( toupper ( callsign [1] ) <= 'X' ) ) strcpy ( lang , "de" ) ; else strcpy ( lang , "??" ) ; /* französisch? */ } /* statistik funktion */ statistic () { char stat_string [256] ; /* response time - nur wenn schon daten vorliegen! */ if ( rt_counter != 0 ) { sprintf ( stat_string , "Average Response Time: %.2f seconds\n" , (float) rt_sum / (float) rt_counter ) ; write ( STDOUT_FILENO , stat_string , strlen ( stat_string ) ) ; /* ggf. auch in mail */ if ( mail_status == 1 ) fwrite ( stat_string , 1 , strlen ( stat_string ) , mail_pipe ) ; } /* später evtl. mehr */ }