#ifdef ournix /* printf("XX %d\n",__LINE__); */ #include "ournix.h" #endif char sccsID[] = "@(#) phone.c V1.8 Copyright Julian H. Stacey, Munich, 1997 01 02-2006.\n"; /* FUNCTION : Filter phone book input to output for estic, isdnd, or gnokii phone table formats LATER allow multiple work phone numbers per person. LATER extend to sort phone book entries by criteria, such as alphabetic by first name. There's no call to free() 'cos I want to later add a sort command. JJLATER maybe allow for '*' '#' 'R' as dial keys. */ #include #include #include #include /* for isalpha */ #define strequ(a,b) (!strcmp(a,b)) #define strnequ(a,b,n) (!strncmp(a,b,n)) typedef char FLAG ; char **ARGV ; FLAG opt_isdn_and_estic = (FLAG)0 ; /* produce lookup table for isdn & estic */ FLAG opt_mobile = (FLAG)0 ; /* produce lookup table for gnokii */ FLAG opt_new_gnokii = #if /*{*/ ( __FreeBSD__ == 4 ) /* { Assume FreeBSD-4.11 with Gnokii-6.4 */ (FLAG)0 ; #else /* }{ Assume FreeBSD-6.2 with Gnokii-6.14 */ (FLAG)1 ; #endif /*}*/ FLAG opt_dflt_exclude = (FLAG)0 ; /* if opt_dflt_exclude is set, exclude all entries lacking "ie:+" */ FLAG opt_estic = (FLAG)0 ; FLAG opt_sort = (FLAG)0 ; FLAG opt_zap = (FLAG)0 ; FLAG opt_capital = (FLAG)0 ; FILE *fp_in ; long line_count ; char *file_name ; char seperator[] = "][" ; size_t seperator_ln ; /* My full international number is (last bit faked) "+49.89.123456" */ #define MY_COUNTRY "49" /* Default international number */ #define MY_TOWN "89" /* Default Town */ #define PREFIX_INTERNATIONAL "00" /* Replace + with 00 for countries */ #define PREFIX_NATIONAL "0" /* Dial 0 to get out of town */ char my_country[20] ; /* typically 49 */ char my_town[20] ; /* typically 89 */ char prefix_international[20] ; /* typically 00 */ char prefix_national[20] ; /* typically 0 */ FLAG num_local = (FLAG)1 ; /* output local within-same-town variant of number, if within your town */ FLAG num_national = (FLAG)1 ; /* output within-same-nation national variant of number, if within your country */ FLAG num_international = (FLAG)1 ; /* output full international number */ FLAG num_one = (FLAG)0 ; /* just one number, the shortest */ FLAG field_printed ; char int_prefix_country[20] ; /* typically 0049 */ char nat_prefix_town[20] ; /* typically 089 */ unsigned ln_nat_prefix_town, ln_int_prefix_country ; unsigned ln_prefix_national, ln_prefix_international ; #define SIM_MAX 100 /* Maximum number of names in a SIM card */ unsigned sim_max = SIM_MAX ; /* Define Maximum names in phone internal memory. */ #if defined NOKIA_6110 /*{{*/ #define PHONE_MAX 50 /* Erik S.: GSM spec requires > 50. */ #elif defined NOKIA_5110 /*}{*/ #define PHONE_MAX 0 /* xgnokii */ #elif defined NOKIA_6210 /*}{*/ #define PHONE_MAX 500 /* Pawel Kot */ #elif defined SONY_CMD_J70 /*}{*/ #define PHONE_MAX 500 #elif defined SONY_PTX_520 /*}{*/ #define PHONE_MAX 500 #else #define PHONE_MAX 50 /* Be conservative, (see eg Nokia above) */ #endif /*}}*/ /* Define maximum length of name to be stored for mobile phones */ #define NAME_LENGTH_MAX 16 #define NAME_LENGTH_MIN 6 /* Nothing special about 6, but program not * written for daft values example <=2, * & probably would crash. */ #ifdef NOKIA_6110 /*{{*/ #define NAME_LENGTH 14 #else /*}{ Assume Sony */ #define NAME_LENGTH 13 #endif /*}}*/ unsigned name_length = NAME_LENGTH ; unsigned phone_max = PHONE_MAX ; #define LINE_LN 1024 char line_buf[LINE_LN] ; #define HOME_INDICATOR "#" /* Hash, as in 4 walls, * Better than 'H' to distinguish * from 'W' & 'M' in poor light. */ #ifdef OLD /*{ gnokii running non FreeBSD-4.7 used to be OK with these but on 4.9 Dollar & and Yen (but not hash) are getting lost, not by this program, but by gnokii wrinting to 6110, they show OK in the gnokii window, but after writing to Nokia 6110 they are no longer visible until/if I fix that, I use boring letters. */ #define WORK_INDICATOR "$" /* Dollar, as in working for money */ #define MOBILE_INDICATOR "\xa5" /* Yen symbol, looks like Aerial */ #else /*}{ So now we use boring letters */ #define WORK_INDICATOR "W" #define MOBILE_INDICATOR "Y" /* Aerial shape, better than M for * Mobile, as horizontal of M * blurs easier into previous * letter. + not all call * it mobile, eg Americans * "Cell" & Germans "Handy". */ #endif /*}*/ #include "person.h" int person_ln ; struct person *first_person, *cur_person ; void init_person(tmp_person) struct person *tmp_person ; { tmp_person->psn_next = (struct person *)0 ; tmp_person->psn_fn = tmp_person->psn_sn = tmp_person->psn_bn = tmp_person->psn_de = tmp_person->psn_co = tmp_person->psn_ah = tmp_person->psn_aw = tmp_person->psn_th = tmp_person->psn_tw = tmp_person->psn_tm = tmp_person->psn_fh = tmp_person->psn_fw = tmp_person->psn_fm = tmp_person->psn_mh = tmp_person->psn_mw = tmp_person->psn_mm = tmp_person->psn_ih = tmp_person->psn_iw = tmp_person->psn_im = tmp_person->psn_ie = tmp_person->psn_cg = tmp_person->psn_tx = tmp_person->psn_eh = tmp_person->psn_ew = tmp_person->psn_wh = tmp_person->psn_ww = tmp_person->psn_sk = tmp_person->psn_cy = tmp_person->psn_ws = tmp_person->psn_sm = tmp_person->psn_ca = tmp_person->psn_oc = tmp_person->psn_na = tmp_person->psn_bo = tmp_person->psn_te = tmp_person->psn_fr = tmp_person->psn_ac = tmp_person->psn_xs = tmp_person->psn_xr = tmp_person->psn_ld = tmp_person->psn_bd = tmp_person->psn_bg = tmp_person->psn_jo = tmp_person->psn_cz = (char *)0 ; } void print_keys() { char *p = "fn:sn:bn:co:ah:aw:th:tw:tm:fh:fw:fm:mh:mw:mm:ih:iw:im:ie:cg:tx:eh:ew:wp:wb:sk:cy:ws:sm:ca:oc:na:bo:te:fr:ac:xs:xr:ld:bd:bg:jo:cz"; while (*p != '\0' ) { if (*p == ':' ) (void)fputc((int)',', stderr) ; else (void)fputc((int)*p, stderr); p++; } (void)fputc((int)'\n', stderr); } /* Returns pointer to address of required field. */ /* LATER: see if enum is supported by MSC V4, & if so shrink field_p etc */ char ** field_p(field,tmp_person) char *field ; struct person *tmp_person; { #define DEFL_ENTRY "cz" if (strequ(DEFL_ENTRY,field)) return( &(tmp_person->psn_cz) ); /* do above 1st for speed*/ if (strequ("fn",field)) return( &(tmp_person->psn_fn) ); if (strequ("sn",field)) return( &(tmp_person->psn_sn) ); if (strequ("bn",field)) return( &(tmp_person->psn_bn) ); if (strequ("de",field)) return( &(tmp_person->psn_de) ); if (strequ("co",field)) return( &(tmp_person->psn_co) ); if (strequ("ah",field)) return( &(tmp_person->psn_ah) ); if (strequ("aw",field)) return( &(tmp_person->psn_aw) ); if (strequ("th",field)) return( &(tmp_person->psn_th) ); if (strequ("tw",field)) return( &(tmp_person->psn_tw) ); if (strequ("tm",field)) return( &(tmp_person->psn_tm) ); if (strequ("fh",field)) return( &(tmp_person->psn_fh) ); if (strequ("fw",field)) return( &(tmp_person->psn_fw) ); if (strequ("fm",field)) return( &(tmp_person->psn_fm) ); if (strequ("mh",field)) return( &(tmp_person->psn_mh) ); if (strequ("mw",field)) return( &(tmp_person->psn_mw) ); if (strequ("mm",field)) return( &(tmp_person->psn_mm) ); if (strequ("ih",field)) return( &(tmp_person->psn_ih) ); if (strequ("iw",field)) return( &(tmp_person->psn_iw) ); if (strequ("im",field)) return( &(tmp_person->psn_im) ); if (strequ("ie",field)) return( &(tmp_person->psn_ie) ); if (strequ("cg",field)) return( &(tmp_person->psn_cg) ); if (strequ("tx",field)) return( &(tmp_person->psn_tx) ); if (strequ("eh",field)) return( &(tmp_person->psn_eh) ); if (strequ("ew",field)) return( &(tmp_person->psn_ew) ); if (strequ("wh",field)) return( &(tmp_person->psn_wh) ); if (strequ("ww",field)) return( &(tmp_person->psn_ww) ); if (strequ("sk",field)) return( &(tmp_person->psn_sk) ); if (strequ("cy",field)) return( &(tmp_person->psn_cy) ); if (strequ("ws",field)) return( &(tmp_person->psn_ws) ); if (strequ("sm",field)) return( &(tmp_person->psn_sm) ); if (strequ("ca",field)) return( &(tmp_person->psn_ca) ); if (strequ("oc",field)) return( &(tmp_person->psn_oc) ); if (strequ("na",field)) return( &(tmp_person->psn_na) ); if (strequ("bo",field)) return( &(tmp_person->psn_bo) ); if (strequ("te",field)) return( &(tmp_person->psn_te) ); if (strequ("fr",field)) return( &(tmp_person->psn_fr) ); if (strequ("ac",field)) return( &(tmp_person->psn_ac) ); if (strequ("xs",field)) return( &(tmp_person->psn_xs) ); if (strequ("xr",field)) return( &(tmp_person->psn_xr) ); if (strequ("ld",field)) return( &(tmp_person->psn_ld) ); if (strequ("bd",field)) return( &(tmp_person->psn_bd) ); if (strequ("bg",field)) return( &(tmp_person->psn_bg) ); if (strequ("jo",field)) return( &(tmp_person->psn_jo) ); fprintf(stderr, "%s Warning: File %s, Line %ld, Field \"%s\" unrecognised, treating as comment.\n", *ARGV, file_name, line_count, field) ; return( &(tmp_person->psn_cz) ); } int get_line() /* return 0 if fail, as on EOF */ { register int this_ch, count = LINE_LN ; char *line_ptr = line_buf, ch ; line_buf[0] = '\0' ; line_count++ ; while((this_ch = getc(fp_in)) != EOF) { ch = (char)this_ch ; if (ch == '\n') { *line_ptr = '\0' ; return( line_ptr - line_buf) ; } *line_ptr++ = ch ; if (--count <= 0) { *--line_ptr = '\0' ; /* The -- loses the ch, but need it to avoid writing beyond array. */ fprintf(stderr, "%s %s: File %s, Line %ld >= %d chars, too long, break inserted\n", *ARGV, #define SAFER 1 /* undef for old behaviour */ #ifdef SAFER "Error", #else "Warning", #endif file_name, line_count, LINE_LN) ; #ifdef SAFER exit(-1); #else return(LINE_LN-1) ; #endif } } /* loop for next char */ if (line_ptr>line_buf) /* flush any last line lacking a \n */ return(line_ptr - line_buf) ; else return(EOF); } /* Append to an entry in a person structure */ void ent_append( to , from) char **to, *from ; { char *new ; int len ; if ((new = realloc( *to, (len=strlen(*to)) + 1 + 1 + strlen(from) + 1 ) ) /* 1st str + \n + space + 2nd str + \0 */ ==(void *)0) {perror("ent_append"); exit(EXIT_FAILURE); } if ((*from == ' ') || (*from == '\t')) sprintf(new+len,"\n%s", from); else /* prepend a space on continuation line */ sprintf(new+len,"\n %s", from); *to = new ; /* I guess *to = new is normally un-necessary, but reading FreeBSD man malloc re. env. var. MALLOC_OPTIONS: R ``realloc'' always reallocate when realloc() is called, even if the initial allocation was big enough. This can substantially aid in compacting memory. */ } /* Gets an entry such as "sn:stacey" (which may have trailing data on * subsequent indented lines). * Return EOF on EOF if no preceeding data. * Return 0 if a person seperator is encountered. * Return 1 if a record is obtained (& don't exit till the whole * of the multi line record is obtained. */ int get_entry(tmp_person) struct person *tmp_person; { char field[3]; char *data, **ptr, *start; int len ; /* On new files input buffer will be empty, but in normal use the read-ahead (necessary to determine if the previous record is terminated) will have already pre-loaded the buffer */ if (line_buf[0]=='\0') { /* load input buffer */ while ((len=get_line()) == 0 ) ; /* discard blank lines */ if (len == EOF) return(EOF); } /* detect inter person seperator */ if (strnequ(seperator,line_buf,seperator_ln)) { line_buf[0] = '\0' ; return(0) ; } if (isalpha(line_buf[0]) && isalpha(line_buf[1]) && (line_buf[2]==':')) { /* new field specifier */ field[0]=line_buf[0]; field[1]=line_buf[1];field[2]='\0'; start=line_buf + 3; } else { /* unspecified data */ strcpy(field,DEFL_ENTRY); start=line_buf ; fprintf(stderr, "%s Warning: File %s, Line %ld, Data \"%s\"\n", *ARGV, file_name, line_count, line_buf) ; } ptr = field_p(field,tmp_person) ; if (*ptr == (char *)0) { if ((data = malloc(strlen(start)+1))==(void *)0) {perror("get_entry 1"); exit(EXIT_FAILURE); } *ptr = data ; strcpy(data,start); } else { /* Entry used previously, so append */ fprintf(stderr, "Warning file: %s, line: %ld, field: %s, appending \"%s\" to \"%s\"\n", file_name, line_count, field, start, *ptr); ent_append( ptr , start); } /* append cascade indented entry extensions */ while (((len=get_line()) != 0 ) && ( len != EOF ) && ((line_buf[0] ==' ') || (line_buf[0] =='\t'))) /* if we happen to get an EOF now, leave it till next get_entry() invocation. */ ent_append( ptr , line_buf); return(1); } int get_person() { struct person *new_person ; int rslt ; if ((new_person = malloc(sizeof(struct person)))==(void *)0) {perror("get_person"); exit(EXIT_FAILURE); } init_person(new_person); if (first_person == (struct person *)0) cur_person= first_person = new_person ; else { cur_person->psn_next = new_person ; cur_person = new_person ; } while((rslt=get_entry(cur_person)) && (rslt != EOF)) ; return(rslt); } /* Receive an empty string & fill it with an incrementing record number */ char * get_index(phone_index) char *phone_index; { static int sim_count=1 ; /* xgnokii starts numbering both at 1 not 0 */ static int phone_count=1 ; if (phone_count == phone_max + 1 ) fprintf(stderr, "Warning: You exceed assumed maximum memory of phone\n"); /* do not abort, that's the phones job later */ sprintf(phone_index,"%s;%d;", ( sim_count <= sim_max ) ? ((opt_new_gnokii == (FLAG)0 ) ? "A" : "SM" ) : ((opt_new_gnokii == (FLAG)0 ) ? "B" : "ME") , ( sim_count <= sim_max ) ? sim_count++ : phone_count++ ) ; return(phone_index); } int get_call_group(call_group,name) char *call_group; char *name; { char *p; if ((p=call_group)==(char *)0) return(5) ; if (*p=='\0') return(5) ; while (*p != '\0') { *p = tolower(*p); p++ ; } p = call_group ; if (strequ("family",p)) return(0); if (strequ("urgent",p)) return(1); if (strequ("social",p)) return(2); if (strequ("business",p)) return(3); if (strequ("club",p)) return(4); if (strequ("default",p)) return(5); if (strequ("no group",p)) return(5); fprintf(stderr,"Unrecognised call group \"%s\" for name \"%s\"\n", p,name); return(5); } void get_file() { line_count = 0L ; line_buf[0] = '\0' ; cur_person = first_person = (struct person *)0 ; while( get_person() != EOF ) ; } int isphone(char *str) { char *ptr ; for (ptr = str ; (isdigit((int)*ptr) || (*ptr == '.') || (*ptr == '+') ) ; ptr++ ) ; if (*ptr == '\0' ) return 1 ; fprintf(stderr, "Error, bad phone number: \"%s\"\n", str); return 0 ; } #define NAME_LN 100 /* Maximum output for fn: sn: or bn: record */ /* in fact all of estic gnokii & isdn want much shorter names */ #define NAME_BIG (3 * NAME_LN + 3) /* 3 is 2 seperators + null */ /* Print a pair of numbers & names as part of a lookup list */ int put_pair(phone, name, location, call_group) char *phone, *name, *location, *call_group ; { char name_int[NAME_BIG]; /* internal copy as external name is passed to us several times & we dont want to succesively append all of MOBILE_INDICATOR WORK_INDICATOR HOME_INDICATOR */ char phone_index[20] ; #define BUFF 200 /* LATER formalise */ char buf1[BUFF], buf2[BUFF] ; char *p1, *p2 ; FLAG num_done = (FLAG)0 ; /* JJLATER Checking is in the wrong place ! Checking should be moved from output procedure to input ! */ /* skip incomplete records, comments beginning with a space etc */ if ( (phone == (char *)0) || (*phone == '\0' ) || (name == (char *)0) || (*name == '\0' ) ) return -1 ; if (*phone == '#') return -1 ; /* hashed out entry, ignore */ if (isspace((int)*phone)) { /* JJLATER add code to be lenient & eat the space */ fprintf(stderr, "Warning: bad entry: \"%s:%s\" \"%s\"\n", (location == (char *)0) ? "" : location , (phone == (char *)0) ? "" : phone , (name == (char *)0) ? "" : name ) ; return -1 ; } #if 1 /*{{*/ if ((p1=strchr(phone,(int)'\n')) != (char *)0) /* unexpected \n, but accept it */ *p1 = '\0' ; p1 = phone ; if ( *p1 == '+') p1++ ; while ( (isdigit ((int)*p1)) || ( *p1 == '.') ) p1++ ; if ( *p1 == '\0' ) goto stripped; /* ideal, no trailing junk */ /* Trailing junk exists beyond number */ p2 = p1 ; if ( *p2 == '#' ) { *p2 = '\0' ; goto stripped; } /* strip white before comment delimiter */ while (isblank ((int)*p2)) p2++ ; if ( *p2 == '\0' ) goto stripped; if ( *p2 == '#' ) { *p1 = '\0' ; goto stripped; } fprintf(stderr, "Warning: bad entry: \"%s:%s\" \"%s\"\n", (location == (char *)0) ? "" : location , (phone == (char *)0) ? "" : phone , (name == (char *)0) ? "" : name ) ; if (isdigit((int)(*p2))) /* Bad format "+49.1234 567890" */ fprintf(stderr, "Warning: discarded numeric %s\n", p2); *p1 = '\0' ; stripped: #else /* }{ old code removed between 2004 May 13 & 2006 Sep 25 */ /* Remove any trailing comment text notes beyond phone number */ if ((p1=strchr(phone,(int)'\t'))!=(char *)0) *p1 = '\0' ; if ((p1=strchr(phone,(int)'\n'))!=(char *)0) /* unexpected */ *p1 = '\0' ; if ((p1=strchr(phone,(int)' '))!=(char *)0) { if (isdigit(*(p1 + 1))) /* Detected bad format "+49.1234 567890" */ fprintf(stderr, "Warning: truncating number with a space: %s\n", phone); *p1 = '\0' ; } #endif /*}}*/ if (*phone == '\0') return -1 ; if (!isphone(phone)) return -1 ; strcpy(name_int,name); /* Capitalise at least First Character of each space seperated name */ if (islower(name_int[0])) name_int[0] = toupper(name_int[0]) ; for(p1 = name_int; *p1 != '\0' ; p1++ ) { if (opt_capital == (FLAG)0) { if ((*p1 == ' ') && islower(*(p1+1))) *(p1+1) = toupper(*(p1+1)); } else /* Capitalise all */ *(p1+1) = toupper(*(p1+1)); } /* Remove all '.' & ',' & '-' & 'x' (x for extension maybe) */ for(p1 = phone, p2 = buf2 ; *p1 != '\0' ; p1++ ) if ((*p1 != '.') && (*p1 != ',') && ( *p1 != '-') && (*p1 != 'x') ) *p2++ = *p1 ; *p2 = '\0' ; if (opt_zap && (strlen(buf2) < 6 )) { /* Remove unlikely short numbers */ return -1 ; } else if (*buf2 == '\0') return -1 ; /* Reduce the number that may be in a local or full international form, to it's mininal form, IE if we are in the same country or town, discard any redundant prefixes */ if (buf2[0] == '+') { /* Convert "+" to "00" */ /* International */ strcpy(buf1,prefix_international); strcat(buf1,buf2 + 1); } else strcpy(buf1,buf2); if (strnequ(buf1,int_prefix_country,ln_int_prefix_country)) { /* Convert "0049" to "0" */ strcpy(buf2,prefix_national); strcat(buf2,buf1 + ln_int_prefix_country); } else strcpy(buf2,buf1); if (strnequ(buf2,nat_prefix_town,ln_nat_prefix_town)) { /* Convert "089" to "" */ strcpy(buf1,buf2 + ln_nat_prefix_town); } else strcpy(buf1,buf2) ; /* buf1 now contains shortest version of number, having removed any town & national prefixes that we are situated in */ if (strlen(buf1) < 3) /* 112 Emergency operator (Fire Police Ambulance) */ /* 140 Alpin Notruf */ /* 6360 Siemens Perlach */ /* 19202 City Ambulanz */ fprintf(stderr, "Warning: suspect short number: \"%s\" \"%s\" \"%s\"\n", buf1 , name_int , location ) ; if (opt_mobile) { /* Append location symbol $ # and Yen/Antenna to names */ if (strequ(location,"TH")|| strequ(location,"TW")|| strequ(location,"TM") ) { name_int[name_length -1] ='\0' ; /* force at least 1 space for HOME_INDICATOR, WORK_INDICATOR, or MOBILE_INDICATOR */ if (strlen(name_int) < name_length - 1) strcat(name_int," ") ; if strequ(location,"TH") strcat(name_int, HOME_INDICATOR ) ; else if strequ(location,"TW") strcat(name_int, WORK_INDICATOR ) ; else if strequ(location,"TM") strcat(name_int, MOBILE_INDICATOR ) ; } } /* Some public exchanges (local offices in American parlance) allow one to dial either the full number including all the international &/or town codes, or the local short form if you are in that town. (My Munich exchange will allow me to dial myself within the 89 city using 089123456, but will not allow me to dial my international self within the 49 nation using 004989 ). As people now rove the world with laptops, making calls via modem & mobile phone, & in case multiple phone logs are merged, we allow more than one number in isdn & istec lists so, Input: th:+49.89.123456 or th:123456 etc Output: 123456 Julian 089123456 Julian 004989123456 Julian But as Nokia mobile in Germany via Deutsch Telekom accepts full +4989123456 syntax, that's what's best to use, & no point storing duplicates. Isdnd reports if I call myself: "Call from 89123456 to 123456" Problem with emergency numbers such as 112 & 0800 ! */ /* Names should not contain a comma, as xgnokii then fails to * to do a text to number conversion when parsing a comma * seperated list of text names of multiple people to SMS * with a single message. */ if (opt_mobile) { char *s_comma ; for (s_comma = name_int ; (s_comma=strchr(s_comma, (int)',' )) != (char *)0 ; *s_comma++ = '&' ) fprintf(stderr, "%s Warning: %s Converting Comma to Ampersand: %s\n", (ARGV == (char **)0) ? "\0" : *ARGV, (file_name == (char *)0 ) ? "\0" : file_name , name_int); /* JJLATER reporting line number too would be useful, so this code should be moved to input test */ } /* Print local town format if wanted & in this town */ if (num_local && ! (strnequ(buf1,prefix_international,ln_prefix_international) || strnequ(buf1,prefix_national,ln_prefix_national))) { if (opt_isdn_and_estic) { if (!opt_estic) printf("%-30s\t\"%s %s\"\n",buf1, location, name_int); /* full name may run off screen, so put location first */ else /* Estic allows 16 chars in a name, EG: "John Smith H" */ printf( "%-30s\t\"%.13s %s\"\n",buf1, name_int,location); /* put person's (short) name before location */ num_done = (FLAG)1 ; } else if (opt_mobile) { /* Mobiles mostly need national or international numbers, not local, as they dont make any assumption which town they are in for normal numbers, unlike terrestial phones; however some few local numbers such as "112"=Emergency need to be left unchanged, so we cant just turn off all local numbers with a num_local = (FLAG)0 ; */ if ( strequ(buf1,/* Debitel: Auskunft */ "11880") || strequ(buf1,/* Debitel: Hotline */ "22210") || strequ(buf1,/* Debitel: Minutes et More */ "2555") || strequ(buf1,/* German: Notruf */ "112" ) || strequ(buf1,/* German: Notruf Alpin */ "140" ) || strequ(buf1,/* German: Polizei */ "110" ) || strequ(buf1,/* T-Mobil: Auskunft/Vermittlung */ "2555") || strequ(buf1,/* T-Mobil: Konto Audio */ "2000") || strequ(buf1,/* T-Mobil: MobilboxAbfrage */ "3311") || strequ(buf1,/* T-Mobil: PannenService */ "2424") || strequ(buf1,/* T-Mobil: SMS-Operator */ "2522") || strequ(buf1,/* T-Mobil: StauInfo Tegaron */ "2211") || strequ(buf1,/* T-Mobil: T-D1 Service Manager */ "2020") || strequ(buf1,/* T-Mobil: TravelService */ "2525") || strequ(buf1,/* T-Mobil: Verkehrs Info */ "2526") || strequ(buf1,/* T-Mobil: Vermittlung */ "2555") || strequ(buf1,/* T-Mobil: Xtra Service 60 */ "2202") || 0 /* blank line above allows a sort with editor */ ) /* A nasty ad hoc table till do it a better way. Perhaps later by defining anything begining with a "-" EG "-112" does not get expanded to +4989112 */ { printf("%s;%s;%s%d%s\n", name_int, buf1, get_index(phone_index), get_call_group(call_group,name_int) , (opt_new_gnokii==(FLAG)0 ) ? ";" : "" ) ; num_done = (FLAG)1 ; } } } /* Print national format if wanted & in this nation */ if (num_national && !(num_done && num_one) && ! strnequ(buf1,prefix_international,ln_prefix_international) ) { buf2[0] = '\0' ; if (!strnequ(buf1,prefix_national,ln_prefix_national)) /* if buf1 is local number */ strcpy(buf2,nat_prefix_town); strcat(buf2,buf1); if (opt_isdn_and_estic) { /* not single gnokii, so print now, as may want both */ if (!opt_estic) /* full name may run off screen, so put location first */ printf("%-30s\t\"%s %s\"\n",buf2, location, name_int); else /* Estic allows 16 chars in a name, put person's (short) name before location */ printf("%-30s\t\"%.13s %s\"\n",buf2, name_int,location); num_done = (FLAG)1 ; } else if (opt_mobile) { printf("%s;%s;%s%d%s\n", name_int, buf2, get_index(phone_index), get_call_group(call_group,name_int), (opt_new_gnokii==(FLAG)0 ) ? ";" : "" ) ; num_done = (FLAG)1 ; } } /* Print international format if wanted */ if (num_international && !(num_done && num_one)) { if (strnequ(buf1,prefix_international,ln_prefix_international) ) /* buf1 is international */ strcpy(buf2,buf1); else if strnequ(buf1,prefix_national,ln_prefix_national) { /* buf1 is national */ strcpy(buf2,int_prefix_country); strcat(buf2,buf1 + ln_prefix_national); } else { /* buf1 is local */ strcpy(buf2,int_prefix_country); strcat(buf2,my_town); strcat(buf2,buf1); } /* now print */ if (opt_isdn_and_estic) { if (opt_estic) /* Estic allows 16 chars in a name, put person's (short) name before location */ printf("%-30s\t\"%.13s %s\"\n",buf2, name_int,location); else /* full name may run off screen, so put location first */ printf("%-30s\t\"%s %s\"\n",buf2, location, name_int); num_done = (FLAG)1 ; } else if (opt_mobile) { /* Convert "00" back to "+" */ strcpy(buf1,"+"); strcat(buf1,buf2 + ln_prefix_international); printf("%s;%s;%s%d%s\n", name_int, buf1, get_index(phone_index), get_call_group(call_group,name_int) , (opt_new_gnokii==(FLAG)0 ) ? ";" : "" ) ; num_done = (FLAG)1 ; } } return 0 ; } /* Trim any hashed trailing comments, then trim trailing white space */ void hash_trim( /* const */ char *ptr0) { char *ptr1 ; if (( ptr0 == (char *)0) || (*ptr0 == '\0')) return ; /* Trim any hashed trailing comments */ if ((ptr1 = index(ptr0, (int)'#')) != NULL ) *ptr1 = '\0' ; /* Trim trailing white space */ for (ptr1 = ptr0 ; /* warning: assignment discards `const' from pointer target type */ *ptr1++ != '\0' ; ) ; ptr1-- ; while (--ptr1 >= ptr0) { if ( isspace((int)*ptr1) ) *ptr1 = '\0' ; break ; } } /* For a lookup list, not for a full output, List all numbers {Telephone,Fax,Modem} x {Home, Work, Mobile} for a person Example output: 01188 "Telefon Auskunft TW" Phone Work 001188 "Int. Auskunft TW" Phone Work 1234567 "Julian Stacey TW" Phone Work 2345678 "Julian Stacey FH" Fax Home 123456 "Fred Smith, IBM" */ void put_short(tmp_person) struct person *tmp_person ; { /* JJLATER add some of tmp_person->psn_de to this procedure */ char names[NAME_BIG] ; char *fn, *sn, *bn, *ie, *cg ; fn=tmp_person->psn_fn; sn=tmp_person->psn_sn; bn=tmp_person->psn_bn; ie=tmp_person->psn_ie; cg=tmp_person->psn_cg; hash_trim(fn); hash_trim(sn); hash_trim(bn); hash_trim(ie) ; hash_trim(cg) ; if ( ((fn == (char *)0) || (*fn == '\0')) && ((sn == (char *)0) || (*sn == '\0')) && ((bn == (char *)0) || (*bn == '\0')) ) return ; if ( opt_mobile && ( ((ie == (char *)0) && ( opt_dflt_exclude == (FLAG)1)) || ((ie != (char *)0) && strequ (ie,"-" ) ) ) ) { #ifdef DEBUG fprintf(stderr,"Skipping %s%s%s\n", (fn != (char *)0) ? fn : "" , ( ((fn != (char *)0) && (*fn != '\0')) && ((sn != (char *)0) && (*sn != '\0')) ) ? " " : "" , (sn != (char *)0) ? sn : "" , ( ((sn != (char *)0) && (*sn != '\0')) && ((bn != (char *)0) && (*bn != '\0')) ) ? "," : "" , (bn != (char *)0) ? bn : "" ) ; #endif return ; } sprintf(names,"%.100s%s%.100s%s%.100s", /* same 100 as NAME_LN */ (fn != (char *)0) ? fn : "" , ( ((fn != (char *)0) && (*fn != '\0')) && ((sn != (char *)0) && (*sn != '\0')) ) ? " " : "" , (sn != (char *)0) ? sn : "" , ( ((sn != (char *)0) && (*sn != '\0')) && ((bn != (char *)0) && (*bn != '\0')) ) ? "," : "" , (bn != (char *)0) ? bn : "" ) ; (void)put_pair(tmp_person->psn_th,names,"TH",cg); (void)put_pair(tmp_person->psn_tw,names,"TW",cg); (void)put_pair(tmp_person->psn_tm,names,"TM",cg); if (opt_isdn_and_estic) { /* Only add "|| opt_mobile" if you need to store fax number in mobile */ (void)put_pair(tmp_person->psn_fh,names,"FH",cg); (void)put_pair(tmp_person->psn_fw,names,"FW",cg); (void)put_pair(tmp_person->psn_fm,names,"FM",cg); } if (opt_isdn_and_estic) { /* Only add "|| opt_mobile" if you need to store modem number in mobile */ (void)put_pair(tmp_person->psn_mh,names,"MH",cg); (void)put_pair(tmp_person->psn_mw,names,"MW",cg); (void)put_pair(tmp_person->psn_mm,names,"MM",cg); } if (opt_isdn_and_estic) { /* Not useful to list isdn data connection numbers in mobile, so skip them for opt_mobile. */ (void)put_pair(tmp_person->psn_ih,names,"IH",cg); (void)put_pair(tmp_person->psn_iw,names,"IW",cg); (void)put_pair(tmp_person->psn_im,names,"IM",cg); } } put_field(field,content) char *field, *content; { if (content != (char *)0) { printf("%s:%s\n",field,content); field_printed = 1 ; } } void put_person(pp) struct person *pp ; { field_printed = 0 ; /* LATER add upper case conversion */ put_field("ld",pp->psn_ld); /* Last update */ /* Contact Info */ put_field("fn",pp->psn_fn); /* Forenames */ put_field("sn",pp->psn_sn); /* Surname */ put_field("bn",pp->psn_bn); /* Business Name */ put_field("de",pp->psn_de); /* Department Name */ put_field("th",pp->psn_th); /* Telephone home */ put_field("tw",pp->psn_tw); /* Telephone work */ put_field("tm",pp->psn_tm); /* Telephone mobile */ put_field("ie",pp->psn_ie); /* Include/Exclude in own mobile */ put_field("fh",pp->psn_fh); /* Fax Home */ put_field("fm",pp->psn_fm); /* Fax Mobile */ put_field("fw",pp->psn_fw); /* Fax Work */ put_field("mh",pp->psn_mh); /* Modem home */ put_field("mw",pp->psn_mw); /* Modem work */ put_field("mm",pp->psn_mm); /* Modem mobile */ put_field("ih",pp->psn_ih); /* ISDN Home */ put_field("iw",pp->psn_iw); /* ISDN Work */ put_field("im",pp->psn_im); /* ISDN Mobile */ put_field("eh",pp->psn_eh); /* Email home */ put_field("ew",pp->psn_ew); /* Email work */ put_field("wh",pp->psn_wh); /* Web Home (personal) */ put_field("ww",pp->psn_ww); /* Web Work (business) */ put_field("ah",pp->psn_ah); /* Address home */ put_field("aw",pp->psn_aw); /* Address work */ put_field("tx",pp->psn_tx); /* Telex */ /* Occupation/Business Info */ put_field("oc",pp->psn_oc); /* Occupation */ put_field("jo",pp->psn_jo); /* Jobs, last approach YYYY.MM.DD */ put_field("cg",pp->psn_cg); /* Call Group for incoming */ put_field("co",pp->psn_co); /* Context EG vsl ukc gea */ /* Leisure Info */ put_field("bg",pp->psn_bg); /* Beer Garden Regular */ put_field("cy",pp->psn_cy); /* Cycle */ put_field("sk",pp->psn_sk); /* Skier */ put_field("ws",pp->psn_ws); /* Windsurfer */ /* Equipment */ put_field("bo",pp->psn_bo); /* Boat (rubber inflatable) */ put_field("ca",pp->psn_ca); /* Car */ put_field("te",pp->psn_te); /* Tent */ /* Personal Info */ put_field("ac",pp->psn_ac); /* Accom share */ put_field("bd",pp->psn_bd); /* Birth date */ put_field("fr",pp->psn_fr); /* Friend */ put_field("na",pp->psn_na); /* Nationality ie GB, D, F */ put_field("sm",pp->psn_sm); /* Smoker */ put_field("xr",pp->psn_xr); /* Xmas Card Received */ put_field("xs",pp->psn_xs); /* Xmas Card Sent */ /* Odd Comments Last */ put_field(DEFL_ENTRY,pp->psn_cz); /* Comment (everything else) */ if ((!( opt_isdn_and_estic || opt_estic || opt_mobile )) && field_printed ) printf("%s\n",seperator); } void put_file() { cur_person = first_person ; while (cur_person != (struct person *)0) { if (opt_isdn_and_estic || opt_mobile) { put_short(cur_person) ; } else put_person(cur_person) ; cur_person = cur_person->psn_next ; } } void sort_file() { /* struct person *low, *high, *tmp ; */ return; /* LATER algorithm incomplete */ #if 0 /*{*/ low = first_person ; while ((low != (struct person *)0) && ((high = low->psn_next) != (struct person *)0)) { if (!(opt_isdn_and_estic || opt_mobile)) { /* Sort by first name. Perhaps later I might sort by surname then by forname, (so all members of a family get listed together), but that wouldnt be useful using mobile phone. JJLATER Maybe I should sort by bn: business name ? */ if (strcmp(low->psn_fn,high->psn_fn)) { tmp = low ; low = high ; high = tmp ; } } else { /* Not much point, as pipe through sort will be better */ if (strcmp(low->psn_th,high->psn_th)) { tmp = low ; low = high ; high = tmp ; } } low = low->psn_next ; } #endif /*}*/ } void do_file() { get_file() ; if (opt_sort) sort_file() ; put_file() ; } void syntax() { fprintf(stderr,"Syntax: %s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", *ARGV, "[-+] ", "[-1] ", "[-?] ", "[-C] ", "[-I international_prefix] ", "[-L] ", "[-N national_prefix] ", "[-S] ", "[-c country_number] ", "[-g] ", "[-G 0] ", "[-G 1] ", "[-i] ", "[-l] ", "[-m] ", "[-n] ", "[-p phone_records] ", "[-s sim_records] ", "[-t town_number] ", "[-w name_length] ", "[-z] ", "-- or File[s]" ) ; fprintf(stderr,"Valid keys are: "); print_keys() ; } void digit(char *str) { int dummy_int; if (sscanf(str,"%d",&dummy_int) != 1 ) /* sscanf is an inadequate test */ { fprintf(stderr, "Fatal Error, Prefix should be numeric: \"%s\"\n", str); syntax(); exit(1); } } int main(argc, argv) int argc ; char **argv ; { int exit_code = 0 ; char *p ; ARGV = argv ; #ifdef VSL /* { */ #include "../../include/vsl.h" #endif /* } */ strcpy(my_country, MY_COUNTRY ); strcpy(my_town, MY_TOWN ); strcpy(prefix_international, PREFIX_INTERNATIONAL ); strcpy(prefix_national, PREFIX_NATIONAL ); for (argc--, argv++ ; argc ; argv++, argc--) { if (**argv != '-') break ; p = *argv + 1 ; while(*p) switch(*p++) /* thus allow "-esz" as well as -e -s */ { case '+': /* Exclude entries lacking an "ie:+". */ opt_dflt_exclude = (FLAG)1 ; break ; case '1': /* just one number */ num_one = (FLAG)1 ; break ; case '?' : syntax() ; exit(0) ; break ; case 'c' : /* "1" for USA, 44 for Britain etc */ if (--argc <= 0) syntax() ; strcpy(my_country, *++argv); break ; case 'g': /* produce gnokii table name:number */ opt_mobile = (FLAG)1 ; break ; case 'G': /* produce gnokii table name:number */ if (--argc <= 0) syntax() ; if ((unsigned)atoi(*++argv) == (FLAG)0) opt_new_gnokii = (FLAG)0 ; else opt_new_gnokii = (FLAG)1 ; opt_mobile = (FLAG)1 ; break ; case 'i': /* no international number */ num_international = (FLAG)0 ; break ; case 'l': /* produce lookup table numbers:names */ opt_isdn_and_estic = (FLAG)1 ; break ; case 'm': /* No local number */ num_local = (FLAG)0 ; break ; case 'n': /* no national variant number */ num_national = (FLAG)0 ; break ; case 'p' : /* phone memory, max number of names */ if (--argc <= 0) syntax() ; phone_max = (unsigned)atoi(*++argv); break ; case 's' : /* sim memory, max. number of names */ if (--argc <= 0) syntax() ; sim_max = (unsigned)atoi(*++argv); break ; case 't' : /* "89" for Munich, by default */ if (--argc <= 0) syntax() ; strcpy(my_town, *++argv); break ; case 'w' : /* phone max name length */ if (--argc <= 0) syntax() ; name_length = (unsigned)atoi(*++argv); if (( name_length > NAME_LENGTH_MAX) || ( name_length < NAME_LENGTH_MIN)) { fprintf(stderr, "-w must be between %d & %d\n", NAME_LENGTH_MIN, NAME_LENGTH_MAX); exit(1); } break ; case 'z': /* zap unlikely short numbers */ opt_zap = (FLAG)1 ; break ; case 'C' : /* Capitalise whole name for small screens */ opt_capital = (FLAG)1 ; break ; case 'I' : /* "00" for international prefix */ if (--argc <= 0) syntax() ; digit(*++argv); strcpy(prefix_international, *argv); break ; case 'L': /* restrict output name for estic */ opt_isdn_and_estic = opt_estic = (FLAG)1 ; break ; case 'N' : /* "0" for national trunk prefix */ if (--argc <= 0) syntax() ; digit(*++argv); strcpy(prefix_national, *argv); break ; case 'S': /* sort output */ opt_sort = (FLAG)1 ; break ; default: fprintf(stderr, "Unknown flag %c\n", *(p-1)) ; syntax(); exit(1); break ; } } if (opt_mobile) { if ( ( ( num_international == (FLAG)0 ) && ( num_national == (FLAG)0 ) ) || ( ( num_international == (FLAG)1 ) && ( num_national == (FLAG)1 ) ) ) { syntax(); fprintf(stderr, "Forcing International rather than national numbers\n"); num_international == (FLAG)1 ; num_national == (FLAG)0 ; } /* we do not test for num_local as some local EG "112" need to be allowed through & not swapped to "+4989112" */ } if (!( num_local || num_national || num_international )) { syntax(); fprintf(stderr, "Error, cannot use all of -i -n -m\n"); fprintf(stderr, "Forcing International numbers\n"); num_international == (FLAG)1 ; } if ((opt_dflt_exclude == (FLAG)1 ) && (opt_mobile == (FLAG)0 )) { syntax(); fprintf(stderr, "Warning: -+ is meaningless without -g.\n"); } seperator_ln = strlen(seperator); person_ln = sizeof(struct person) ; sprintf(int_prefix_country,"%s%s",prefix_international,my_country); sprintf(nat_prefix_town,"%s%s",prefix_national,my_town); ln_int_prefix_country = strlen(int_prefix_country); ln_nat_prefix_town = strlen(nat_prefix_town); ln_prefix_national = strlen(prefix_national); ln_prefix_international = strlen(prefix_international); if (argc == 0) { file_name = "stdin" ; fp_in = stdin ; do_file() ; exit(0) ; } else do { file_name = *argv++ ; fp_in = fopen(file_name, "r") ; if (fp_in == (FILE *)0) { fprintf(stderr, "Cannot open '%s'\n",file_name) ; exit_code |= EXIT_FAILURE ; continue ; } do_file() ; (void) fclose(fp_in) ; } while (--argc) ; exit(exit_code) ; }