/* ipass_fetch - fetch billing data from i-Pass web site Copyright (c) 1997 i-Pass Alliance Inc. All rights reserved. This software may be used and modified by i-Pass Alliance partners solely in accordance with the terms and conditions of the applicable i-Pass membership agreement. Please report any portability problems to support@ipass.com Usage: ipass_fetch [options] Valid options are: -i print available billing dates on stdout -f bill_date fetch data for the specified bill_date -o directory specify output directory (default is /tmp) -v turn on debugging messages on stderr With no options, a usage message is displayed. Original version - March 1997 */ #include #include #include #include /* Network API */ #include #include #include /* Define your i-Pass userid and password here */ char *userid = "999"; char *passwd = "pw999"; /* Define the i-Pass web server address here */ char *server = "www.ipass.com"; char *server_port = "80"; char *root_path = "/partnersonly/PER_MEMBER/"; /*char *root_path = "/channel/PER_MEMBER/";*/ /* local function prototypes */ FILE *get (char *name); FILE *open_output (char *fname); char *encode(char *userid, char *passwd); char *dup_string(char *s); /* local data */ int ns = -1; /* socket to server */ int verbose = 0; char *output_dir = "/tmp"; char *bill_date = ""; char base64[] = /* base64 encoding table */ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; struct file_spec { char *name; void *next; }; struct file_spec *file_list = NULL; /* The main program */ main (int argc, char **argv) { extern int optind; extern char *optarg; int c; int opt_count = 0; int do_index = 0; int do_fetch = 0; /* process options */ while ((c = getopt (argc,argv,"vif:o:")) != EOF) { switch (c) { case 'v': verbose = 1;; break; case 'i': do_index = 1;; opt_count++; break; case 'f': bill_date = optarg; do_fetch = 1;; opt_count++; break; case 'o': output_dir = optarg; break; case '?': usage(1); break; } } /* handle the specified request */ if (opt_count == 0) usage(0); if (opt_count > 1) { trace("Too many options specified."); usage(1); } if (do_index) show_index(); else if (do_fetch) fetch_billing(bill_date); exit(0); } /* show_index - display index of available billing dates looks for lines starting with next = file_list; new->name = dup_string(p1); file_list = new; } net_close(); /* fetch the list of files */ fs = file_list; while (fs) { fetch_data_file(fs->name); fs = fs->next; } } /* fetch_data_file - fetch a data file Copies data contents of name.htl to output_dir/name */ fetch_data_file (char *fname) { char name[1024]; char buff[1024]; FILE *in, *ofile; int status; net_open(); strcpy(name,bill_date); strcat(name,"/"); strcat(name,fname); in = get(name); status = skip_header(in); if (status != 0) { net_close(); fatal(status,name); } /* open output file */ ofile = open_output(fname); trace("fetching %s ...",fname); while (fgets(buff,sizeof(buff),in)) { /* skip html lines */ if (*buff == '<') continue; /* copy data lines */ fprintf(ofile,buff); } fclose(ofile); } /* skip_header - skip http lines If error, the HTTP/1.0 status code is returned (e.g. 302, 401), otherwise 0 is returned. */ skip_header (FILE *in) { char buff[1024]; int status = 0; while (fgets(buff,sizeof(buff),in)) { if (*buff == '\r' || *buff == '\n') break; if (strncmp(buff,"HTTP/1.0 ",9) == 0) { sscanf(buff+9,"%d",&status); if (verbose) trace("HTTP status = %d",status); } if (verbose) { strtok(buff,"\r\n"); fprintf(stderr,"Header <%s>\n",buff); } } /* decode status codes */ if (status == 200 || status == 302) return(0); return(status); } /* open_output - open an output file in the output directory */ FILE *open_output (char *fname) { FILE *ofile; char path[1024]; char *p; strcpy(path,output_dir); strcat(path,"/"); strcat(path,fname); p = strstr(path,".htm"); if (p) *p = '\0'; ofile = fopen(path,"w"); if (ofile == NULL) { trace("Can't open output file %s",path); exit(1); } return(ofile); } /* net_open - establish connection to server */ net_open () { /* open a socket to the i-Pass web server */ ns = net_connect(server,server_port); if (ns < 0) return(-1); return(0); } /* net_close - close connection to server */ net_close () { close(ns); ns = -1; } /* get - issue an http get for a specified file Returns FILE handle from which the output may be read */ FILE *get (char *name) { static FILE *in; FILE *out; char path[2048]; /* get the pathname */ build_path(path,name); /* issue GET request */ out = fdopen(ns,"w"); in = fdopen(ns,"r"); if (verbose) trace("GET %s HTTP/1.0",path); fprintf(out,"GET %s HTTP/1.0\n",path); fprintf(out,"Authorization: Basic %s\n\n",encode(userid,passwd)); fflush(out); return(in); } /* build_path - build the PER_MEMBER pathname */ build_path (char *path, char *name) { strcpy(path,root_path); strcat(path,userid); strcat(path,"/billing/"); strcat(path,name); } usage (int status) { trace("Usage: ipass_fetch [options]"); trace("-i print available billing dates on stdout"); trace("-f bill_date fetch data for the specified bill_date "); trace("-o directory specify output directory (default is /tmp)"); trace("-v turn on debugging messages on stderr"); exit(status); } /* net_connect - get a client socket connection to host Returns file descriptor for connection */ net_connect (char *host, char *port) { int port_num; int err; struct servent *sp; struct hostent *hp; struct sockaddr_in sin; int s; /* can specify either a port number or a service name */ if (0 == sscanf(port,"%d",&port_num)) { sp = (struct servent *) getservbyname(port, "tcp"); if (sp == 0) { trace("net_connect: unknown service '%s/tcp'",port); return(-1); } port_num = sp->s_port; } /* get the destination host */ hp = gethostbyname(host); if (hp == 0) { trace("net_connect: unknown host '%s'", host); return(-1); } /* create a socket */ s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { trace( "net_connect: socket: %s", strerror(errno)); return(-1); } /* try to connect */ sin.sin_family = hp->h_addrtype; memcpy((caddr_t)&sin.sin_addr, hp->h_addr_list[0],hp->h_length); sin.sin_port = htons(port_num); if (verbose) trace("connecting to <%s> on port %d ...",host,port_num); err = connect(s, (struct sockaddr *)&sin, sizeof (sin)); if (err < 0) { close(s); trace("net_connect: connect: %s",strerror(errno)); return(-1); } if (verbose) trace("connected to <%s> on port %d",host,port_num); return(s); } /* encode - encode userid/passwd into the 6 bit encoding scheme returns a static string */ char *encode (char *userid, char *passwd) { static char output[1024]; char input[1024]; int count, len, i, remainder; /* build input string */ strcpy(input,userid); strcat(input,":"); strcat(input,passwd); /* add on 2 extra zero bytes at end */ len = strlen(input); *(input+len+1) = '\0'; *(input+len+2) = '\0'; /* process input in groups of 3 bytes */ count = len/3; for (i=0; i> 2; v2 = ((*ip & 0x03) << 4) | (*(ip+1) >> 4); v3 = ((*(ip+1) & 0x0f) << 2) | (*(ip+2) >> 6); v4 = *(ip+2) & 0x3f; /* encode the values */ *op++ = base64[v1]; *op++ = base64[v2]; *op++ = base64[v3]; *op++ = base64[v4]; } /* dup_string - create a copy of a string */ char *dup_string (char *s) { char *new; new = (char *) malloc(strlen(s)+1); if (!new) { trace("malloc error"); exit(1); } strcpy(new,s); return(new); } /* fatal - handle fatal http error */ fatal (int status, char *name) { char path[1024]; build_path(path,name); if (status == 401) trace("Incorrect userid or password"); else if (status == 404) trace("File does not exist: %s",path); else trace("Request failed, error code = %d",status); trace(" - request was: GET %s",path); } trace(char *fmt, int p1, int p2, int p3, int p4) { char buff[1024]; sprintf(buff,fmt,p1,p2,p3,p4); fprintf(stderr,"%s\n",buff); }