//// bidwatcher // copyright (c) 1999-2005 // Trent McNair (trent@rmci.net) // Tom McNair (tmcnair@cyberhighway.net) // Wayne Schlitt (wayne@midwestcs.com) // Ben Byer (bushing@users.sourceforge.net) // Kevin Dwyer (kevin@pheared.net) // // use of this code is restricted to the terms // of the GNU GPL, which should have been included in this // distribution. If not, see www.gnu.org/copyleft/gpl.html. // Here is the short version: // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // helpers.cpp: // // Helper functions for bidwatcher, no platform/gui specific // code. // #include "config.h" #include #include #ifdef HAVE_SSTREAM # include #else # ifdef HAVE_STRSTREAM_H # include # endif #endif #include #include #include #include #include #include "bidwatcher.h" #include "portability.h" #ifdef HAVE_SSTREAM typedef std::istringstream StringBuffer; #else typedef std::istrstream StringBuffer; #endif const char * const CheckPrice="0123456789.$,"; // Characters allowed in a price const char * const SearchOps[2][37]={{ "Starts at", // 1 "Currently", // 2 "First bid", // 3 "Quantity", // 4 "# of bids", // 5 "Time left", // 6 "Item location", // 7 "Started", // 8 "Ends", // 9 "Seller (Rating)", // 10 "High bid", // 11 "Bid increment", // 12 "This is a ", // 13 "Lowest", // 14 "(Reserve ", // 15 "Current bid", // 16 "Starting bid", // 17 "Seller (rating)", // 18 "High bidder", // 19 "Price:", // 20 "Seller information", // 21 "History", // 22 "Winning bid:", // 23 "Winning bidder:", // 24 "Sold for", // 25 "Buyer:", // 26 "Bidding has ended", // 27 // for some reason theBuyItNow/Purchase only // auction have a space in front of "Price". " Price", // 28 "Feedback Score:", // 29 "(", // 30 "Ended:", // 31 "Shipping and handling:", // 32 "Shipping Cost Services Available", // 33, newer version of above " price:", // 34 "price:", // 35 "Seller information", // 36 "*"}, /* eBay Motors */ { "Currently", // 1 "Time left ", // 2 "Seller (rating) ", // 3 "High bid ", // 4 "# of bids ", // 5 "Location ", // 6 "Started ", // 7 "ends ", // 8 "Starts at", // 9 "(reserve ", // 10 "Current bid", // 11 "Ends ", // 12 "Starting bid", // 13 "High bidder", // 14 "*" } }; void strnzcpy(char *dst, const char *src, size_t len) { strncpy(dst, src, len); dst[len] = 0; } int strnzcmp(const char *str1, const char *str2) { return strncmp(str1, str2, strlen(str2)); } bool strToFloat(const char *str, float &x) { return (sscanf(str, "%f", &x) == 1); } float calculateBidIncrement(float currentBid, const char *currency) { // step 1 - parse currentBid into useable int's /* int err; char curBid[15]; if ( currentBid[0] == '$' ) { int limit = strlen(currentBid); for ( int i=0; i < limit; i++ ) { // strip the '$' off the currentBid; curBid[i] = currentBid[i + 1]; } curBid[14] = '\0'; // because I'm insane } else { strcpy(newBid, "no bids"); return; } */ float fcb = currentBid; // fcb = 'float current bid' float inc; switch(currency[0]) { case '$': // all three types of dollars have the same increments // it's official! :) case 'U': // US dollar case 'A': // australian dollars case 'C': // canadian dollars if (fcb < 1.00) inc = 0.05; else if (fcb < 5.00) inc = 0.25; else if (fcb < 25.00) inc = 0.50; else if (fcb < 100.00) inc = 1.00; else if (fcb < 250.00) inc = 2.50; else if (fcb < 500.00) inc = 5.00; else if (fcb < 1000.00) inc = 10.00; else if (fcb < 2500.00) inc = 25.00; else if (fcb < 5000.00) inc = 50.00; else inc = 100.00; break; case 'G': // great british pounds inc=100; if (fcb<3000) inc=50; if (fcb<1500) inc=20; if (fcb<600) inc=10; if (fcb<300) inc=5; if (fcb<150) inc=2; if (fcb<60) inc=1; if (fcb<15) inc=0.50; if (fcb<5.00) inc=0.20; if (fcb<1) inc=0.05; break; case 'J': // japanese yen inc=12000; if (fcb<=600000) inc=7500; if (fcb<=300000) inc=3000; if (fcb<=120000) inc=1200; if (fcb<=60000) inc=600; if (fcb<=30000) inc=240; if (fcb<=12000) inc=120; if (fcb<=3000) inc=60; if (fcb<=600) inc=30; if (fcb<=120) inc=5; break; case 'D': // deutsche marks (german, obsolete) inc=100; if (fcb<10000) inc=10; if (fcb<1000) inc=5; if (fcb<100) inc=1; break; case 'E': // Euro inc = 50; if(fcb < 5000) inc = 10; if(fcb < 1000) inc = 5; if(fcb < 500) inc = 1; if(fcb < 50) inc = 0.5; break; default: fprintf(stderr, "unknown currency %s\n", currency); inc=0; } fcb = fcb + inc; return fcb; } char translate_special(const char *input, int *len) { // Does translation of special characters in HTML // of the format &XXXX; *len = strstr(input, ";") - input - 1; char temp[11]; memset(temp, 0, sizeof(temp)); if (*len < 10) { // Is this reasonable? strnzcpy(temp, input+1, *len); (*len)++; // So we erase everything later if (strchr(temp, '\'')) // Illegal character return 0; if (!strcmp(temp, "#9")) return '\t'; if (!strcmp(temp, "#38") || !strcmp(temp, "amp")) return '&'; if (!strcmp(temp, "#34") || !strcmp(temp, "quot") || !strcmp(temp, "#39") || !strcmp(temp, "#174") || !strcmp(temp,"raquo") || !strcmp(temp,"laquo") || !strcmp(temp, "#8220") || // lower double-quote !strcmp(temp, "#8222") || // upper double-quote !strcmp(temp, "quot") || // double-quote !strcmp(temp, "#8221") || !strcmp(temp, "rsquo") || !strcmp(temp, "ndash") || !strcmp(temp, "trade") || !strcmp(temp, "bull")) return '\"'; if (!strcmp(temp, "#37")) return '%'; if (!strcmp(temp, "#169")) return 0xA9; // '©'; if (!strcmp(temp, "#174")) return 0xAE; // '®'; if (!strcmp(temp, "#8211") || !strcmp(temp, "#8212")) return '-'; // Unicode "en dash" character if (!strcmp(temp, "szlig")) return 223; // sz-ligature if (!strcmp(temp, "nbsp") || !strcmp(temp, "copy") || !strcmp(temp, "#8260") || !strcmp(temp, "#12288") || !strcmp(temp, "#9674") || !strcmp(temp, "#8730")) return ' '; if (!strcmp(temp, "middot")) // This should be trademark return ' '; if (!strcmp(temp, "#8482")) // This should be trademark return ' '; if (!strcmp(temp, "#8364") || !strcmp(temp,"euro")) // euro sign return '¤'; if (!strcmp(temp, "lt") || !strcmp(temp, "#60")) return '<'; if (!strcmp(temp, "gt") || !strcmp(temp, "#62")) return '>'; if (!strcmp(temp, "#8217") || !strcmp(temp, "#146")) return '\''; if (!strcmp(temp, "deg")) return 0xB0; // '°'; if (!strcmp(temp, "pound")) return 0xA3; // '£'; if (!strcmp(temp, "plusmn")) return 0xB1; // '±'; if (!strcmp(temp, "micro")) return 0xB5; // 'µ'; if (!strcmp(temp, "reg")) return 0xAE; // '®'; if (!strcmp(temp, "aacute")) return 0xE1; // 'á'; if (!strcmp(temp, "Aacute")) return 0xC1; // 'Á'; if (!strcmp(temp, "aelig")) return 0xE6; // 'æ'; if (!strcmp(temp, "AElig")) return 0xC6; // 'Æ'; if (!strcmp(temp, "agrave")) return 0xE0; // 'à'; if (!strcmp(temp, "Agrave")) return 0xC0; // 'À'; if (!strcmp(temp, "aring")) return 0xE5; // 'å'; if (!strcmp(temp, "Aring")) return 0xC5; // 'Å'; if (!strcmp(temp, "auml")) return 0xE4; // 'ä'; if (!strcmp(temp, "Auml")) return 0xC4; // 'Ä'; if (!strcmp(temp, "ccedil")) return 0xE7; // 'ç'; if (!strcmp(temp, "Ccedil")) return 0xC7; // 'Ç'; if (!strcmp(temp, "eacute")) return 0xE9; // 'é'; if (!strcmp(temp, "Eacute")) return 0xC9; // 'É'; if (!strcmp(temp, "egrave")) return 0xE8; // 'è'; if (!strcmp(temp, "Egrave")) return 0xC8; // 'È'; if (!strcmp(temp, "oslash")) return 0xF8; // 'ø'; if (!strcmp(temp, "Oslash")) return 0xD8; // 'Ø'; if (!strcmp(temp, "ouml")) return 0xF6; // 'ö'; if (!strcmp(temp, "Ouml")) return 0xD6; // 'Ö'; if (!strcmp(temp, "uuml")) return 0xFC; // 'ü'; if (!strcmp(temp, "Uuml")) return 0xDC; // 'Ü'; if (!strcmp(temp, "brvbar")) return '|'; if (!strcmp(temp, "#8230")) // ellipsis return '.'; else { if ((*len > 1) && (temp[0] == '#')) { fprintf(stderr, "Got unknown HTML entity '%s' (0x%X)\n", temp, atoi(temp+sizeof(char))); } else { // We don't know what it is fprintf(stderr, "Got unknown HTML entity '%s'\n", temp); } return 0; } } else return 0; } /////////////////////////////////////////////////////////////////////////////// // StripHtmlTags() // -strips the tags off an html string // Thanks to Bob Beaty! /////////////////////////////////////////////////////////////////////////////// char *StripHtmlTags(const char *stringToStrip) { int buffLength = strlen(stringToStrip); #if DEBUGGING > 0 #warning "Buffer is double its normal size" char *Buff = (char *) malloc(buffLength*2 + 1); memset(Buff, 0, buffLength*2 + 1); #else char *Buff = (char *) malloc(buffLength + 1); memset(Buff, 0, buffLength + 1); #endif int BuffIdx = 0; int u,c; int SaveIncludeFlag=5, IncludeFlag; // states of IncludeFlag: // 1 - HTML double quote text // 2 - a comment // 3 - java script // 5 - within a HTML statement // 10 - content (and no HTML stuff) IncludeFlag = 5; // strip up everything before the first tag, too // strip the html tags for (u = 0; u < buffLength; u++) { c = stringToStrip[u]; if (c == '<') { IncludeFlag=5; if(u+3') { Buff[BuffIdx++] = '\n'; u+=2; } else if (stringToStrip[u+1] == 't' && \ stringToStrip[u+2] == 'd' && \ stringToStrip[u+3] == '>' && BuffIdx > 0 && !isspace(Buff[BuffIdx - 1])) { Buff[BuffIdx++] = ' '; u+=2; } else if (stringToStrip[u+1] == 'b' && \ stringToStrip[u+2] == 'r' && \ stringToStrip[u+3] == '>') { Buff[BuffIdx++] = '\n'; u+=2; } else if (stringToStrip[u+1] == '!' && \ stringToStrip[u+2] == '-' && \ stringToStrip[u+3] == '-') { IncludeFlag=2; u+=3; } } } else if (c == '"' && IncludeFlag < 10) { if (IncludeFlag != 1) { SaveIncludeFlag = IncludeFlag; IncludeFlag = 1; } else { IncludeFlag = SaveIncludeFlag; } continue; } else if (IncludeFlag == 1 && c != '"') { continue; } else if (c == '\\' && stringToStrip[u+1] == '>') { u += 1; continue; } else if (c == '>' && IncludeFlag < 10 && IncludeFlag >= 5) { IncludeFlag=10; } else if (c == '-' && u+1') { Buff[BuffIdx++] = '\n'; IncludeFlag=10; u+=2; } else { u+=1; } } else if (IncludeFlag==10) { if ((BuffIdx > 0) && (c == ' ') && (Buff[BuffIdx-1] != ' ') && (Buff[BuffIdx-1] != '\n')) Buff[BuffIdx++] = ' '; else if ((BuffIdx > 0) && (c == ' ') && (Buff[BuffIdx-1] != ' ')) continue; /* ignore -- crunch multiple spaces */ else if ((BuffIdx > 0) && (c == '\n') && (Buff[BuffIdx-1] != '\n')) Buff[BuffIdx++] = c; else if (c == '&') { int charlen = 0; // Try to find the end of the char sequence &XXX; if (strstr(&stringToStrip[u], ";") != NULL) Buff[BuffIdx] = translate_special(&stringToStrip[u], &charlen); if (Buff[BuffIdx] != 0) u += charlen; // If it was 0, we didn't know what it was, proceed as normal. if (Buff[BuffIdx] == 0) Buff[BuffIdx] = c; BuffIdx++; } else if ((c > 31) && (c < 127)) Buff[BuffIdx++] = c; else if (c == -96) Buff[BuffIdx++] = ' '; // Weird non-space character. else if (c == -106) Buff[BuffIdx++] = '-'; // Windows' "en dash" (\226) character else if ((c > -96) && (c < 0)) { Buff[BuffIdx++] = c; //printf("c[%i]=%c\n", c, c); } } } if (BuffIdx == 0) Buff[0] = '\0'; else Buff[BuffIdx - 1] = '\0'; return Buff; } ////////////////////////////////////////////////////////////////////// // StripAndTab - strips html tags off an html buffer and inserts // tabs where each tag goes, this aids in parsing later ////////////////////////////////////////////////////////////////////// char * StripAndTab(const char * stringToStrip) { int buffLength = strlen(stringToStrip); int BuffIdx = 0; int u,c; int IncludeFlag = 5; bool tabFlag = FALSE; char *Buff=(char *)malloc(buffLength + 1); memset(Buff, 0, buffLength + 1); for (u = 0; (u < buffLength);u++) { c = stringToStrip[u]; if (c=='<') { tabFlag = FALSE; IncludeFlag=5; } else if (c=='>') { tabFlag = TRUE; IncludeFlag=10; } else if (IncludeFlag==10) { if (tabFlag) { Buff[BuffIdx++] = '\t'; tabFlag = FALSE; } if (((c>31) && (c<127)) || (c=='\n')) Buff[BuffIdx++]=c; } } /* We may not have added any characters */ if (BuffIdx == 0) Buff[0] = '\0'; else /* Terminate the string */ Buff[BuffIdx - 1] = '\0'; return Buff; } void strip_commas(char *p) { int i, j, len; len = strlen(p); for(i = 0, j = 0; i <= len; i++) if (p[i] != ',') p[j++] = p[i]; p[j] = '\0'; } // I really should merge these two. void strip_newlines(char *p) { unsigned int j=0; for(unsigned int i=0; i <= strlen(p); i++) { if (p[i] != '\n') p[j++] = p[i]; else p[j++] = '/'; } p[j] = '\0'; } void strip_crlf(char *p) { int i, j, len; len = strlen(p); for(i = 0, j = 0; i <= len; i++) if (p[i] != '\r' && p[i] != '\n') p[j++] = p[i]; p[j] = '\0'; } ////////////////////////////////////////////////////////////////////////////////// // ProcessBidSubmission // takes the html response from submitting a bid and returns an appropriate // error code. // return values: // 1 - bid submission was a success - we are the high bidder // 2 - Bid too low // 3 - Quantity Problem // 4 - Other problem (unknown, probably bad connection) // ////////////////////////////////////////////////////////////////////////////////// int ProcessBidSubmission(char *Buff, char *lineBuff, int lineBuffLen) { #ifdef HAVE_SSTREAM std::istringstream streamBuff(Buff); #else std::istrstream streamBuff(Buff); #endif bool foundKey = FALSE; // We want to leave lineBuff in a state that has the snipe // key in it so we can use it later. while (streamBuff) { streamBuff.getline(lineBuff, lineBuffLen, '\n'); if (strstr(lineBuff, "name=\"key\"")) { foundKey = TRUE; return PBS_SUCCESS; } else if (strstr(lineBuff, "Confirm that your bid is correct")){ if (foundKey) return PBS_SUCCESS; } else if (strstr(lineBuff, "Problem with bid amount") || (strstr(lineBuff, "Your bid must be at least"))) return PBS_BIDTOOLOW; else if (strstr(lineBuff, "Problem with quantity")) return PBS_BADQUANTITY; else if (strstr(lineBuff, "Cannot proceed") || strstr(lineBuff, "Auction ended")) return PBS_AUCTIONOVER; else if (strstr(lineBuff, "Pre-approval Required")) return PBS_PREAPPROVAL; } return ERROR; } ////////////////////////////////////////////////////////////////////////////// // ProcessBid() // takes the html response from making a bid // return values: // 1 - bid submission was a success - we are the high bidder // 2 - bid successful, but we were outbid. // 3 - bid under the current asking price // 4 - problem with the bid quantity // 5 - Auction is over. // 6 - invalid username / password. // 7 - unknown error // ////////////////////////////////////////////////////////////////////////////// int ProcessBid(char *Buff) { char lineBuff[1024]; #ifdef HAVE_SSTREAM std::istringstream streamBuff(Buff); #else std::istrstream streamBuff(Buff); #endif while (streamBuff) streamBuff.getline(lineBuff, 1024, '\n'); char userURL[100]; snprintf(userURL, 100, "requested=%s", authID); if (strstr(Buff, "are the current high bidder")) return PB_HIGHBID; else if (strstr(Buff, "currently one of the high bidders")) return PB_HIGHBID; else if (strstr(Buff, "outbid you")) return PB_OUTBID; else if (strstr(Buff, "You have been outbid")) return PB_OUTBID; else if (strstr(Buff, "Problem with bid amount")) return PB_BIDTOOLOW; else if (strstr(Buff, "Problem with quantity")) return PB_BADQUANTITY; else if (strstr(Buff, "Cannot proceed")) return PB_AUCTIONOVER; else if (strstr(Buff, "or password invalid") || strstr(Buff, "password is not valid")) return PB_BADUSER; // Do we see our username info URL? else if (strstr(Buff, userURL)) return PB_HIGHBID; // So, it's not us, is it someone else? else if (strstr(Buff, "ReturnUserEmail&requested=")) return PB_OUTBID; fprintf(stderr, "Bid failed - unable to parse eBay's response.\n"); DPRINTF(DHIGH, ("%s", Buff)); return ERROR; } /* /////////////////////////////////////////////////////////////////////////////// // ParseEmailAddress // parses the email address out of the web paged passed in Html. // return values: // 1 - success // 2 - authorization failure // 2 - unknown error /////////////////////////////////////////////////////////////////////////////// int ParseEmailAddress(char * Buff, char * emailAddress) { char tempBuff[1024]; if (strstr(Buff, "password invalid") != NULL) return PEA_BADUSER; if (strstr(Buff, "via e-mail:") == NULL) return ERROR; // now the likely errors are weeded - so we can parse the // email address out of Buff #ifdef HAVE_SSTREAM std::istringstream buffStream(Buff); #else std::istrstream buffStream(Buff); #endif while (buffStream) { buffStream.getline(tempBuff, 1024, '\n'); if ((strstr(tempBuff, "via e-mail:")) != NULL) { // parse the last little bit char * scratch; scratch = strtok(tempBuff,":"); scratch = strtok(0,"\n"); if (scratch) { // now scrape off the leading space, there has to be a better way int limit = strlen(scratch); for (int i =0; i < limit; i++) scratch[i] = scratch[i+1]; strcpy(emailAddress, scratch); } } } return PEA_SUCCESS; } */ /////////////////////////////////////////////////////////////////////////////// // ParseList // Parses auction information from the listings or bidders list pages. // Returns a 0-terminated array of ids of auctions in which we've participated /////////////////////////////////////////////////////////////////////////////// unsigned long long *ParseList(char *Buff) { char lineBuff[2048]; unsigned int nlpos; unsigned long long ids[512], numids=0; unsigned long long *retval; unsigned int i; while(*Buff) { // Get the next line if (strchr(Buff,'\n') == NULL) nlpos = strlen(Buff) - 1; else nlpos = strchr(Buff,'\n') - Buff; strnzcpy(lineBuff, Buff, nlpos); Buff += nlpos + 1; // This is a particularly lame check. Numeric usernames are possible if ((lineBuff[0] == '\t') && (isdigit(lineBuff[1])) && (isdigit(lineBuff[2])) && (isdigit(lineBuff[3])) && (isdigit(lineBuff[4])) && (isdigit(lineBuff[8]))) { ids[numids++] = atoull(lineBuff+1); DPRINTF(DLOW, ("Read id "LLU_FMT"\n", ids[numids-1])); } } retval = (unsigned long long *) malloc(sizeof(unsigned long long) * (numids+1)); for(i=0; i < numids; i++) retval[i] = ids[i]; retval[i] = 0; return retval; } ////////////////////////////////////////////////////////////////////////////// // CheckBadChars // aids GetAucInfo in parsing html correctly ////////////////////////////////////////////////////////////////////////////// void CheckBadChars(char *Str2Chk, char *GoodChars) { int idx,idx2; for (idx=0;Str2Chk[idx]!=0;++idx) { for (idx2=0;GoodChars[idx2]!=0;++idx2) { if (GoodChars[idx2]==Str2Chk[idx]) break; } if (GoodChars[idx2]==0) { Str2Chk[idx]=0; return; } } } ////////////////////////////////////////////////////////////////////////////// // ReturnBidVarNum ////////////////////////////////////////////////////////////////////////////// int ReturnBidVarNum(char *LineData, int auc_type) { int idx=0; int ops_type; // Whoops, ebay motors !car is the same as regular if (auc_type == TYPE_EBAYMOTORS) ops_type = 0; else ops_type = auc_type; // Watch the change, it's strNcmp now. for(idx=0; SearchOps[ops_type][idx][0]!='*';++idx) { if (strncmp(LineData, SearchOps[ops_type][idx], strlen(SearchOps[ops_type][idx]))==0) { return (idx+1); } } return 0; } ////////////////////////////////////////////////////////////////////////////// // ClearBidMakeUp: // Clears the information in a BidMakeup struct ////////////////////////////////////////////////////////////////////////////// void ClearBidMakeUp(struct auctioninfo * NewAuction) { NewAuction->ItemNumber=0; NewAuction->Description[0]=0; NewAuction->CurrentBid=0; NewAuction->FirstBid=0; NewAuction->Quantity=0; NewAuction->BidCount=0; NewAuction->TimeLeft[0]=0; NewAuction->Location[0]=0; NewAuction->Started[0]=0; NewAuction->Ends[0]=0; NewAuction->Seller[0]=0; NewAuction->HighBidder[0]=0; NewAuction->BidInc[0]=0; NewAuction->SellerRate[0] = 0; NewAuction->BidderRate[0] = 0; NewAuction->snipeAmount = 0; NewAuction->snipeQty = 0; NewAuction->myBidAmount=0; NewAuction->myBidQuantity=0; NewAuction->snipeKey[0] = 0; NewAuction->stat = '0'; NewAuction->reserveMet = '0'; NewAuction->isSnipe = FALSE; NewAuction->isPreBid = FALSE; NewAuction->EndsValue = 0; NewAuction->UpdTime = 0; NewAuction->BuyitNowPrice=0; NewAuction->Feedbackn[0] = 0; if (NewAuction->infourl) delete NewAuction->infourl; if (NewAuction->infourl) delete NewAuction->bidurl; NewAuction->infourl=NULL; NewAuction->bidurl=NULL; for(size_t i = 0; i < sizeof(NewAuction->Shipping) / sizeof(NewAuction->Shipping[0]); i++) { NewAuction->Shipping[i] = 0; NewAuction->ShippingCur[i][0] = 0; } } ////////////////////////////////////////////////////////////////////////////// // CalcEndsValue // // takes ebay format ending time (i.e. xx/xx/xx, xx:xx:xx) and converts // it to time in seconds since a epoch (jan 1, 1970), this is for easy // sorting later. // ////////////////////////////////////////////////////////////////////////////// long int CalcEndsValue(char *Ends) { if (strlen(Ends) > 12) { // convert Ends into in values of year, month, day char tokEnds[50]; // the tokenized Ends, will be tossed. STRNZCPY(tokEnds, Ends); char * scratch; int seconds,minutes,hours,month,day,year; scratch = strtok(tokEnds, "/"); if (scratch) month = atoi(scratch); else return -1; scratch = strtok(0,"/"); if (scratch) day = atoi(scratch); else return -1; scratch = strtok(0," "); if (scratch) year = atoi(scratch); else return -1; scratch = strtok(0,":"); if (scratch) hours = atoi(scratch); else return -1; scratch = strtok(0,":"); if (scratch) minutes = atoi(scratch); else return -1; scratch = strtok(0," \0"); if (scratch) seconds = atoi(scratch); else return -1; if (year < 25) year = year + 100; struct tm TheTime; TheTime.tm_sec = seconds; TheTime.tm_min = minutes; TheTime.tm_hour = hours; TheTime.tm_mday = day; TheTime.tm_mon = month - 1; TheTime.tm_year = year; TheTime.tm_yday = 0; TheTime.tm_wday = 0; TheTime.tm_isdst = -1; // now we have day,month,year,minutes,hours,seconds in integer format, // we just need to convert it to seconds since the epoch and we're in // business. long int the_time = mktime(&TheTime); return the_time; } else return -1; } ////////////////////////////////////////////////////////////////////////////// // CalcTimeLeft // calculates the time left in an auction in seconds. // stringTimeLeft // calculates the time left and return a string of that value ////////////////////////////////////////////////////////////////////////////// long int CalcTimeLeft (long int endTime, int ebayOffset) { long int localTime = time(NULL); localTime += ebayOffset; return (endTime - localTime); } int stringTimeLeft (struct auctioninfo *auc, int ebayOffset, char *chTimeLeft) { long int endTime = auc->EndsValue; long int localTime = time(NULL); localTime += ebayOffset; int intTimeLeft = (endTime - localTime); int err; if (auc->isEndless) { err = sprintf(chTimeLeft, "Purchase Only"); return intTimeLeft; } else if (intTimeLeft >= 172800) { err = sprintf(chTimeLeft, "%d days, %d hrs", intTimeLeft / 86400, (intTimeLeft % 86400) / 3600); return intTimeLeft; } else if (intTimeLeft >= 86400) { err = sprintf(chTimeLeft, "%d day, %d hrs", intTimeLeft / 86400, (intTimeLeft % 86400) / 3600); return intTimeLeft; } else if (intTimeLeft >= 3600) { err = sprintf(chTimeLeft, "%d hrs, %d mins", intTimeLeft / 3600, (intTimeLeft % 3600) / 60); return intTimeLeft; } else if (intTimeLeft >= 60) { err = sprintf(chTimeLeft, "%d mins, %d secs", intTimeLeft / 60, intTimeLeft % 60); return intTimeLeft; } else if (intTimeLeft >= 0) { err = sprintf(chTimeLeft, "%d seconds", intTimeLeft); return intTimeLeft; } else { err = sprintf(chTimeLeft, "Auction Ended"); return intTimeLeft; } } ////////////////////////////////////////////////////////////////////////////// // translate_date // converts dates from "Jan-23-00 12:34:56" into "01/23/00, 12:34:56" ////////////////////////////////////////////////////////////////////////////// void translate_date(char *date) { int i; char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; if (isdigit(*date)) return; for(i = 0; i < 12; i++) { if (strncasecmp(date, months[ i ], 3) == 0) break; } if (i >= 12) return; if (date[3] != '-' || date[6] != '-' || date[9] != ' ') return; sprintf(date, "%02d", i+1); date[2] = '/'; date[3] = date[4]; date[4] = date[5]; date[5] = '/'; date[6] = date[7]; date[7] = date[8]; date[8] = ','; } bool parseprice(char currency[], float &price, char *buf) { char *p = strchr(buf, ':'); if(p) buf = p + 1; int len; if ((buf[0]=='$') || (buf[0]=='U' && buf[1]=='S')) { strcpy(currency, "$"); } else { strnzcpy(currency, buf, 6); len = strcspn(currency," 0123456789"); currency[len] = '\0'; } len = strcspn(buf,"0123456789"); buf += len; // skip to price len = strspn(buf,"0123456789.,"); buf[len] = '\0'; strip_commas(buf); bool ret = strToFloat(buf, price); DPRINTF(DLOW, ("buf='%s'\n", buf)); DPRINTF(DLOW, ("Price is '%s' '%.2f' (%s)\n", currency, price, ret ? "OK" : "FAILED")); return ret; } // Parse out currency and price bool parseprice(char *buf,struct auctioninfo * auc, bool isfirst) { if (isfirst) return parseprice(auc->currency, auc->FirstBid, buf); else return parseprice(auc->currency, auc->CurrentBid, buf); } bool parseprice2(char *buf,struct auctioninfo * auc, bool isfirst) { return parseprice(auc->currency, auc->BuyitNowPrice, buf); } static void getShipHandling33(StringBuffer &streamBuff, char *LineData, const int LineDataSize, float ship[], char currency[][10], int num_ship) { for(int i = 0; i < num_ship; i++) { streamBuff.getline(LineData, LineDataSize, '\n'); if(strnzcmp(LineData, "Will ship") == 0) break; if(!parseprice(currency[i], ship[i], LineData)) { ship[i] = 0; break; } } } static void getShipHandling32(StringBuffer &streamBuff, char *LineData, const int LineDataSize, float ship[], char currency[][10], int num_ship) { for(int i = 0; i < num_ship; i++) { streamBuff.getline(LineData, LineDataSize, '\n'); for(int j = 0; j < 10 && LineData[0] == 0; j++) { streamBuff.getline(LineData, 1024, '\n'); } if(strnzcmp(LineData, "Will ship") == 0) break; if(!strchr(LineData, ':')) break; streamBuff.getline(LineData, 1024, '\n'); if(strnzcmp(LineData, "Will ship") == 0) break; if(!parseprice(currency[i], ship[i], LineData)) { ship[i] = 0; break; } } } class AutoCharArray { public: AutoCharArray(size_t size): m_size(size), m_buf(new char[size + 1]) {} ~AutoCharArray() { if(m_buf) delete[] m_buf; m_buf = 0; m_size = 0; } char *buf() const { return m_buf; } size_t size() const { return m_size; } private: AutoCharArray(const AutoCharArray &); AutoCharArray &operator=(const AutoCharArray &); size_t m_size; char *m_buf; }; ////////////////////////////////////////////////////////////////////////////// // GetAucInfo // loads up BidMakeup[] with auction info. ////////////////////////////////////////////////////////////////////////////// bool auctioninfo::parseaucinfo(const char *Buff) { if(getenv("BIDWATCHER_DEVEL")) { char *home = getenv("HOME"); if(home) { char fname[256]; sprintf(fname, "%s/%s/parse.txt", home, bw_subdir); FILE *fp = fopen(fname, "w"); if(fp) { fputs(Buff, fp); fclose(fp); } } } unsigned int idx=0; int cnt; int ended_early=0; int auc_type=TYPE_EBAY; AutoCharArray LineBuffer(strlen(Buff)); char *scratch; char newName[76]; char LineBuffertmp[1024]; int bid_flag=0 ; int first_flag=0; int quant_flag=0; int dutch_flag=0; int buynow_flag = 0; int has_ended_flag = 0; // First Lets clear out the right bits of the structure memset(TimeLeft, 0, sizeof(TimeLeft)); memset(Location, 0, sizeof(Location)); memset(Started, 0, sizeof(Started)); memset(Ends, 0, sizeof(Ends)); memset(Seller, 0, sizeof(Seller)); memset(HighBidder, 0, sizeof(HighBidder)); reserveMet = 'x'; CurrentBid = 0; // Not resetting this breaks the logic of updating the bid BidCount = 0; // This too. /* * Parse the description out of the buffer first. This is * most easily done at the buffer-level and not as we try * to read the buffer in a line-oriented manner. There is * probably a need to re-write this parser all together, * but that's not what I'm going to do right now. * Thanks to Bob Beaty! */ scratch = strstr(Buff, "eBay: "); if (scratch != NULL) { DPRINTF(DLOW, ("found 'eBay:' in auction, new type, scanning...\n")); // move past the "eBay: " scratch += strlen("eBay: "); // move past any whitespace while (isspace(*scratch)) scratch++; // copy over the description to a newline idx = 0; while (*scratch != '\n' && idx < sizeof(Description) - 1) { Description[idx++] = *scratch++; } // NULL terminate the description I just parsed off Description[idx-1] = '\0'; } else { scratch = strstr(Buff, "eBay Motors: "); if (scratch != NULL) { DPRINTF(DLOW, ("found 'eBay Motors:' in auction. New type. Scanning...\n")); // move past the "eBay Motors:" scratch += 12; // move past any whitespace while (isspace(*scratch)) scratch++; // copy over the description to a newline idx = 0; while (*scratch != '(' && idx < sizeof(Description) - 1) { Description[idx++] = *scratch++; } // NULL terminate the description I just parsed off Description[idx-1] = '\0'; DPRINTF(DLOW, ("Auction name = '%s'\n", Description)); } else { DPRINTF(DLOW, ("no mandatory matching 'eBay:' nor 'eBay Motors:' in buffer\n")); return FALSE; } } StringBuffer streamBuff(Buff); /* Skip everything before the start of auction data */ memset(LineBuffer.buf(), 0, LineBuffer.size()); while(strstr(LineBuffer.buf(),"eBay")==NULL && streamBuff) streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (strstr(LineBuffer.buf(),"eBay: ") == NULL) if (strstr(LineBuffer.buf(),"eBay Motors: ") == NULL) { DPRINTF(DLOW, ("no matching 'eBay:' nor 'eBay Motors:' in buffer. Failed.\n")); return FALSE; } if (strstr(LineBuffer.buf(),"eBay Motors:") != NULL) auc_type = TYPE_EBAYMOTORSCAR; while(strstr(LineBuffer.buf()," (item")==NULL && streamBuff) streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if ( strstr(LineBuffer.buf(),"Another buyer used Buy It Now to purchase the item immediately") == NULL ){ scratch = strstr(Buff, "Another buyer used Buy It Now to purchase the item immediately"); if (scratch != NULL) { if (strlen(Comments) > 0) { if ( strstr(Comments, "Sold! BuyitNow") == NULL) { strcpy(scratch,"Sold! BuyitNow "); strcat(scratch,Comments); strcpy(Comments,scratch); } } else { if ( strstr(Comments, "Sold! BuyitNow") == NULL) strcpy(Comments, "Sold! BuyitNow"); } } } if ( strstr(LineBuffer.buf(),"Auction ended early with Buy It Now") == NULL ){ scratch = strstr(Buff, "Auction ended early with Buy It Now"); if (scratch != NULL) { if (strlen(Comments) > 0) { if ( strstr(Comments, "Sold! BuyitNow") == NULL) { strcpy(scratch,"Sold! BuyitNow "); strcat(scratch,Comments); strcpy(Comments,scratch); } } else { if ( strstr(Comments, "Sold! BuyitNow") == NULL) strcpy(Comments, "Sold! BuyitNow"); } } } if ( strstr(LineBuffer.buf(),"The seller ended this listing early") == NULL ){ scratch = strstr(Buff, "The seller ended this listing early"); if (scratch != NULL) { if (strlen(Comments) > 0) { if ( strstr(Comments,"The seller ended this listing early") == NULL ){ strcpy(scratch,"The seller ended this listing early "); strcat(scratch,Comments); strcpy(Comments,scratch); } } else { if ( strstr(Comments,"The seller ended this listing early") == NULL ) strcpy(Comments,"The seller ended this listing early"); } } } if ( strstr(LineBuffer.buf(),"Item has ended") == NULL ){ scratch = strstr(Buff,"Item has ended"); if (scratch != NULL) { has_ended_flag = 1; isEndless = 0; } } if ( strstr(LineBuffer.buf(),"price:") == NULL ){ scratch = strstr(Buff, "price:"); if (scratch != NULL) { scratch = strstr(Buff, "is the winner"); if (scratch != NULL) isBuyitNow = 0; else isBuyitNow = 1; } } if (auc_type == TYPE_EBAYMOTORSCAR) { scratch = strstr(Buff, "Current bid"); if (scratch != NULL) { scratch = strstr(Buff, "Starting bid"); if (scratch != NULL) { // This is totally crazy and will break as soon as they muck with // the html but it works for now to distinguish a Car auction from // a part or accessory. Anyone want to offer a better suggestion? //Should move us ahead to a $. This check is here to make sure //we aren't looking at something the seller said in his desc etc. scratch +=16; if (scratch[0] == '$') auc_type = TYPE_EBAYMOTORS; } } } DPRINTF(DHIGH, ("Auction Type=%i\n", auc_type)); AuctionType = auc_type; while (streamBuff) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); // The Idea here is to get the info we can get, if for // some reason some of the data is missing or out of // order we can still salvage what we can.. // This new case style I came up with is a bit redundant, but // it may allow for bidwatcher to grow into more types. Like // Checking yahoo or something. See also SearchOps. -kdwyer if (LineBuffer.buf()[0]!=0) { int matchedPhrase = ReturnBidVarNum(LineBuffer.buf(), auc_type); if (matchedPhrase != 0) DPRINTF(DLOW, ("MATCHED :%i (%s)\n", matchedPhrase, LineBuffer.buf())); //if (matchedPhrase != 0) fprintf(stderr, "### %d\n", matchedPhrase); //printf("LD:%s:%i\n", LineBuffer.buf(), strlen(LineBuffer.buf())); switch (auc_type) { case TYPE_EBAYMOTORS: //non-car auctions are the same case TYPE_EBAY: switch (matchedPhrase) { case 33: // shipping + handling getShipHandling33(streamBuff, LineBuffer.buf(), LineBuffer.size(), Shipping, ShippingCur, sizeof(Shipping) / sizeof(Shipping[0])); break; case 32: // shipping + handling getShipHandling32(streamBuff, LineBuffer.buf(), LineBuffer.size(), Shipping, ShippingCur, sizeof(Shipping) / sizeof(Shipping[0])); break; case 1: case 2: // current price case 14: // "Lowest" -shows up on motorsnotcars case 16: case 17: case 23: case 25: // "Sold for" if (!bid_flag) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); DPRINTF(DLOW, ("LDCB: %s\n", LineBuffer.buf())); parseprice(LineBuffer.buf(), this, FALSE); bid_flag = 1; isEndless = 0; streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (strstr(LineBuffer.buf(), "reserve not")) reserveMet = 'n'; else if (strstr(LineBuffer.buf(), "reserve met")) reserveMet = 'y'; else // Not a reserve auction, put the chars back. for (unsigned int i=0; i<=strlen(LineBuffer.buf()); i++) streamBuff.unget(); } break; case 3: // first bid case 30: if (strstr(LineBuffer.buf(), "(PayPal account required)")) break; if (!FirstBid && !first_flag && strnzcmp(LineBuffer.buf(), "(Approximately")) { if (!dutch_flag) { DPRINTF(DLOW, ("LDFB: %s\n", LineBuffer.buf())); first_flag=1; char TmpLine[18]; strcpy(TmpLine,":"); strcat(TmpLine,LineBuffer.buf()+1); strcpy(LineBuffer.buf(),TmpLine); parseprice(LineBuffer.buf(), this, TRUE); } if (dutch_flag) FirstBid = CurrentBid; } break; case 20: // "Price:" - BuyItNow Only. case 28: case 34: case 35: DPRINTF(DLOW, ("This is a BuyItNow\n")); if (!buynow_flag) { buynow_flag = 1; int limit = strlen(LineBuffer.buf()); if ( limit < 7 ) { strcpy(LineBuffertmp,LineBuffer.buf()); streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); strcat(LineBuffertmp,LineBuffer.buf()); strcpy(LineBuffer.buf(),LineBuffertmp); } scratch = strstr(LineBuffer.buf(), ":"); if (*(scratch+1) == '\n') streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); //strcpy(LineBuffer.buf(),scratch); parseprice2(scratch, this, FALSE); if (!CurrentBid ) { parseprice(scratch, this, TRUE); } if (!BidCount) { if (!CurrentBid) CurrentBid = BuyitNowPrice; strcpy(BidderRate, "(0)"); FirstBid = CurrentBid; if (has_ended_flag == 0 && !bid_flag) isEndless = 1; } } break; case 4: // quantity if (!Quantity && !quant_flag) { quant_flag=1; if (strchr(LineBuffer.buf(), ':')) streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); CheckBadChars(LineBuffer.buf(), "0123456789"); Quantity = atoi(LineBuffer.buf()); DPRINTF(DLOW, ("LDBC: %s\n", LineBuffer.buf())); } break; case 5: // bid count case 22: if (!BidCount) { DPRINTF(DLOW, ("LDBC: %s\n", LineBuffer.buf())); // if instead of the number of bids an item has "Purchases" and // there was no time left in the auction the auction is not endless int limit = strlen(LineBuffer.buf()); if ( limit < 9 ) { strcpy(LineBuffertmp,LineBuffer.buf()); streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); strcat(LineBuffertmp,LineBuffer.buf()); strcpy(LineBuffer.buf(),LineBuffertmp); } scratch = strchr(LineBuffer.buf(), ':'); if(scratch) { int limit = strlen(scratch); for ( int i=0; i < limit; i++ ) { // strip the ':' off the currentBid; scratch[i] = scratch[i + 1]; } BidCount = atoi(scratch); if (!BidCount) { FirstBid = CurrentBid; strcpy(HighBidder, "--"); strcpy(BidderRate, "(0)"); } } else { fprintf(stderr, "cannot determine BidCount: propably parser broken\n"); } DPRINTF(DLOW, ("BidCount: %i\n", BidCount)); } break; case 6: // time left if (!TimeLeft[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(TimeLeft, LineBuffer.buf()); if (strstr(LineBuffer.buf(), "Auction has ended")) { //DBS ended_early = 1; //DBS } // since there is time left the auction cannot be endless. } break; case 27: // Item has ended ended_early =1; // if the item has ended it is obviously not endless. break; case 7: // location if (!Location[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Location, LineBuffer.buf()); // Dutch Auctions if (Quantity > 1 ) { strcpy(HighBidder, "Dutch Auction"); strcpy(BidderRate, ""); dutch_flag=1; } } break; case 8: // time started if (!Started[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Started, LineBuffer.buf()); translate_date(Started); } break; case 9: // time ending if (!Ends[0]) { //streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); //DPRINTF(DLOW, ("LDE: %s\n", LineBuffer.buf())); STRNZCPY(Ends, LineBuffer.buf() + strlen("Ends ")); translate_date(Ends); EndsValue = CalcEndsValue(Ends); } break; case 31: // ended if (!Ends[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); //DPRINTF(DLOW, ("LDE: %s\n", LineBuffer.buf())); STRNZCPY(Ends, LineBuffer.buf()); translate_date(Ends); EndsValue = CalcEndsValue(Ends); has_ended_flag = 1; isEndless = 0; } break; case 10: // seller id case 18: case 21: case 36: if (!Seller[0]) { unsigned int count; streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (*LineBuffer.buf() == '\0') streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Seller, LineBuffer.buf()); for (count=0; count < sizeof(Seller); count++) { if (Seller[count] == '(') { Seller[count] = 0; // truncate string at first '(' break; // ignore the rest } } // Seller Rate is typicaly in next line, but without leading '(' streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (!strchr(LineBuffer.buf(), ')')) streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (!strchr(LineBuffer.buf(), ')')) break; // validity check SellerRate[0] = '('; for (count=1; count < sizeof(SellerRate)-1; count++) { if (LineBuffer.buf()[count-1] == '\0' || LineBuffer.buf()[count-1] == ')' || LineBuffer.buf()[count-1] == ' ') break; SellerRate[count] = LineBuffer.buf()[count-1]; } SellerRate[count] = ')'; SellerRate[count+1] = '\0'; } break; case 11: // high bidder id case 19: case 24: case 26: // "Buyer:" if (!HighBidder[0]) { char *p; p = strchr(LineBuffer.buf(), ':'); if (p) { if (*(p+1) == '\0') { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); p = LineBuffer.buf(); } else p++; } else { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); p = LineBuffer.buf(); } STRNZCPY(HighBidder, p); p = strchr(HighBidder, '('); if(p) *p = 0; // Bidder Rate is typicaly in next line, but without leading '(' streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (!strchr(LineBuffer.buf(), ')')) streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (!strchr(LineBuffer.buf(), ')')) break; // validity check BidderRate[0] = '('; unsigned int count; for (count=1; count < sizeof(BidderRate)-1; count++) { if (LineBuffer.buf()[count-1] == '\0' || LineBuffer.buf()[count-1] == ')' || LineBuffer.buf()[count-1] == ' ') break; BidderRate[count] = LineBuffer.buf()[count-1]; } BidderRate[count] = ')'; BidderRate[count+1] = '\0'; } break; //case 12: idx=GetLineOfData(idx, 1024, LineBuffer.buf(), Buff); // CheckBadChars(LineBuffer.buf(), CheckPrice); // STRNZCPY(BidInc, LineBuffer.buf()); // break; case 13: // dutch auction streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (!strcmp(LineBuffer.buf(), "Dutch Auction")) strcpy(HighBidder, "Dutch Auction"); break; case 29: if (!Feedbackn[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Feedbackn, LineBuffer.buf()); streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); char TmpLine[6]; unsigned int count; int limit = strlen(LineBuffer.buf()); int iiii=0; for (count=0; count < strlen(LineBuffer.buf()); count++) { if (LineBuffer.buf()[count] == ':') { LineBuffer.buf()[count] = count; // truncate string at first ':' for (int fb=count+1; fb < limit; fb++) { TmpLine[iiii] = LineBuffer.buf()[fb + 1]; iiii++; } } } CheckBadChars(Feedbackn,"0123456789"); if ( strstr(LineBuffer.buf(),"Feedback") != NULL) { int a1=6, c1=strlen(Feedbackn); while (c1 < a1) { /* adds spaces */ strcat(Feedbackn, " "); c1++; } strcat(Feedbackn,TmpLine); } else { CheckBadChars(Feedbackn,"123456789"); STRNZCPY(Feedbackn,"NONE"); } } break; case 15: // reserve auctions if (strstr(LineBuffer.buf(),"Reserve not")) reserveMet = 'n'; else if (strstr(LineBuffer.buf(),"Reserve met")) reserveMet = 'y'; default:; } break; /* End case 0 of auc_type */ case TYPE_EBAYMOTORSCAR: //printf("LD:%s:%i\n", LineBuffer.buf(), strlen(LineBuffer.buf())); switch(matchedPhrase) { case 1: // Current Bid case 9: case 11: case 13: if (!CurrentBid) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); parseprice(LineBuffer.buf(), this, FALSE); streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); if (strstr(LineBuffer.buf(), "reserve not")) reserveMet = 'n'; else if (strstr(LineBuffer.buf(), "reserve met")) reserveMet = 'y'; else if (strstr(LineBuffer.buf(), "Time left")) TimeLeft[0] = '0'; } break; case 2: //Time left if (!TimeLeft[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(TimeLeft, LineBuffer.buf()); } break; case 3: //Seller if (!Seller[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Seller, LineBuffer.buf()); } break; case 14: case 4: //High bid if (!HighBidder[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(HighBidder, LineBuffer.buf()); } break; case 5: //Number of bids if (!BidCount) { char bc[80]; streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); for(cnt=0; (((LineBuffer.buf()[cnt]!=' ') && (LineBuffer.buf()[cnt]!=0)) && (cnt<14)); ++cnt) bc[cnt] = LineBuffer.buf()[cnt]; bc[cnt] = 0; BidCount = atoi(bc); } break; case 6: //Location if (!Location[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Location, LineBuffer.buf()); } break; case 7: //Started if (!Started[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Started, LineBuffer.buf()); translate_date(Started); } break; case 12: case 8: //Ends if (!Ends[0]) { streamBuff.getline(LineBuffer.buf(), LineBuffer.size(), '\n'); STRNZCPY(Ends, LineBuffer.buf()); translate_date(Ends); } break; case 10: // reserve auctions if (strstr(LineBuffer.buf(), "reserve not")) reserveMet = 'n'; else if (strstr(LineBuffer.buf(), "reserve met")) reserveMet = 'y'; default:; break; /* End case 1 of auc_type */ } default:; /* End of switch(auc_type) */ } } } // if ( CurrentBid == 0 ) strcpy(CurrentBid, "Error"); // now calculate the ending time in seconds and save it if the auction ended // early due to cancel or "buy it now" if ( strcmp(Seller, authID) == 0) ended_early = 0; if (ended_early == 1) { isEndless = 0; } // now We'll parse the High Bidder and Seller's ratings off their names // and assign them to .SellerRate and .BidderRate strcpy(newName, Seller); DPRINTF(DLOW, ("Seller: %s %s\n", Seller, SellerRate)); scratch = strtok(newName, " "); //if (!scratch) return FALSE; if (scratch) { strcpy(Seller, scratch); scratch = strtok(0, ")"); if (scratch) { strcpy(SellerRate, scratch); strcat(SellerRate, ")"); } } if(!buynow_flag) { isBuyitNow = 0; BuyitNowPrice = 0; } if (buynow_flag || (!strcmp(HighBidder, "Dutch Auction")) || (!strcmp(HighBidder, "see Dutch high bidders")) || (!strcmp(HighBidder, "--"))) { return TRUE; } else if (!strcmp(HighBidder, "User ID kept private")) { strcpy(HighBidder, "private"); // it's nicer to have this text in log return TRUE; } else { strcpy(newName, HighBidder); scratch = strtok(newName, " "); if (scratch) { strcpy(HighBidder, scratch); scratch = strtok(0, ")"); if (scratch) { strcpy(BidderRate, scratch); strcat(BidderRate, ")"); } } else { strcpy(HighBidder, "--"); strcpy(BidderRate, "(0)"); } DPRINTF(DLOW, ("HighBidder: %s %s\n", HighBidder, BidderRate)); } return TRUE; } // end GetAucInfo() void MakeFileName(char * prefix2, char * fileName, bool thisMonth) { char * homedir=getenv("HOME"); int month,year; time_t time_now = time(0); struct tm * timeStruct = localtime(&time_now); if (thisMonth) month = timeStruct->tm_mon + 1; else month = timeStruct->tm_mon; year = timeStruct->tm_year; if (year > 99) year = year - 100; if (year > 75) sprintf(fileName, "%s%s%d_%d.txt",homedir, prefix2, month, year); else sprintf(fileName, "%s%s%d_0%d.txt",homedir,prefix2, month, year); } void MakeClockTime(int offSet, char * theTime) { time_t intTime = time(NULL) + offSet; //struct tm tmTime = *localtime(&intTime); //int err = sprintf(theTime,"%d:%d:%d", tmTime.tm_hour, tmTime.tm_min, tmTime.tm_sec); //return; char * tempTime = ctime(&intTime); char * scratch = strtok(tempTime, " "); if (!scratch) return; scratch = strtok(0, " "); if (!scratch) return; scratch = strtok(0, " "); if (!scratch) return; scratch = strtok(0, " "); if (!scratch) return; strcpy(theTime, scratch); return; } ////////////////////////////////////////////////////////////////////////////// // calcTimeDiff // // buffer is an unfiltered webpage from ebay containing the // current time (http://cgi.ebay.com/aw-cgi/eBayISAPI.dll?TimeShow) // // calcTimeDiff parses the time from the above mentioned page and // calculates the difference between ebay time and local time, returning // the value in seconds. ////////////////////////////////////////////////////////////////////////////// int calcTimeDiff ( char * buffer) { struct timeval time_tt; //time_t new_time_t = time(NULL); gettimeofday(&time_tt, 0); time_t new_time_t = time_tt.tv_sec; char chHr[9] = ""; char chMin[9] = ""; char chSec[9] = ""; char chYear[9] = ""; char chMonth[9] = ""; char chDay[9] = ""; char *lineBuff; char *scratch; struct tm ebay_time; ebay_time.tm_isdst = -1; lineBuff = new char[strlen(buffer) + 1];; strcpy(lineBuff, buffer); scratch = strstr(lineBuff, "Monday"); if (!scratch) scratch = strstr(lineBuff, "Tuesday"); if (!scratch) scratch = strstr(lineBuff, "Wednesday"); if (!scratch) scratch = strstr(lineBuff, "Thursday"); if (!scratch) scratch = strstr(lineBuff, "Friday"); if (!scratch) scratch = strstr(lineBuff, "Saturday"); if (!scratch) scratch = strstr(lineBuff, "Sunday"); if (scratch) { scratch = strtok(scratch, " "); if (scratch) scratch = strtok(0, " "); if (scratch) strcpy(chMonth, scratch); scratch = strtok(0, " "); if (scratch) strcpy(chDay, scratch); scratch = strtok(0, " "); if (scratch) strcpy(chYear, scratch); scratch = strtok(0,": "); if (scratch) strcpy(chHr, scratch); scratch = strtok(0,":"); if (scratch) strcpy(chMin, scratch); scratch = strtok(0, " "); if (scratch) strcpy(chSec, scratch); scratch = strtok(0, "<"); } delete[] lineBuff; ebay_time.tm_hour = (((int(chHr[strlen(chHr) - 2])) - 48) * 10) + ((int(chHr[strlen(chHr) - 1])) - 48); ebay_time.tm_min = (((int(chMin[strlen(chMin) - 2])) - 48) * 10) + ((int(chMin[strlen(chMin) - 1])) - 48); ebay_time.tm_sec = (((int(chSec[strlen(chSec) - 2])) - 48) * 10) + ((int(chSec[strlen(chSec) - 1])) - 48); ebay_time.tm_mday = atoi(chDay); if (strcmp("Jan", chMonth) == 0) ebay_time.tm_mon = 0 ; else if (strcmp("Feb", chMonth) == 0) ebay_time.tm_mon = 1; else if (strcmp("Mar", chMonth) == 0) ebay_time.tm_mon = 2; else if (strcmp("Apr", chMonth) == 0) ebay_time.tm_mon = 3; else if (strcmp("May", chMonth) == 0) ebay_time.tm_mon = 4; else if (strcmp("Jun", chMonth) == 0) ebay_time.tm_mon = 5; else if (strcmp("Jul", chMonth) == 0) ebay_time.tm_mon = 6; else if (strcmp("Aug", chMonth) == 0) ebay_time.tm_mon = 7; else if (strcmp("Sep", chMonth) == 0) ebay_time.tm_mon = 8; else if (strcmp("Oct", chMonth) == 0) ebay_time.tm_mon = 9; else if (strcmp("Nov", chMonth) == 0) ebay_time.tm_mon = 10; else ebay_time.tm_mon = 11; ebay_time.tm_year = atoi(chYear) - 1900; time_t theTime = mktime(&ebay_time) - new_time_t; DPRINTF(DHIGH, ("Our time: %li eBay time: %li\n", new_time_t, mktime(&ebay_time))); return theTime; } ////////////////////////////////////////////////////////////////////////////// // parseRows // parses rows from raw html and puts them each on a line (if it // finds a newline character in a line it converts it to a space). ////////////////////////////////////////////////////////////////////////////// char * parseRows(const char * fromBuff) { // we have 2 states: (1) we are inside a row or (2) we are not. // to determine we are in a row we need to find "", to determine // we are out we need to find . bool inRow = FALSE; int bufflen = strlen(fromBuff); char * toBuffer=(char *)malloc(bufflen+1); int i,j; i = j = 0; bool inComment = false; for ( i=0; i') { i+=2; inComment = false; } // If we're inside an HTML comment, throw chars out. if (inComment == true) continue; if ((inRow==FALSE) && (fromBuff[i] == '<') && (tolower(fromBuff[i + 1]) == 't') && (tolower(fromBuff[i + 2]) == 'r')) { // we have found a cell and should start recording inRow = TRUE; toBuffer[j++] = fromBuff[i]; } else if ((inRow==TRUE) && (fromBuff[i - 3] == '/') && (tolower(fromBuff[i - 2]) == 't') && (tolower(fromBuff[i - 1]) == 'r') && (fromBuff[i] == '>')) { inRow = FALSE; toBuffer[j++] = fromBuff[i]; toBuffer[j++] = '\n'; } else if (inRow == TRUE) { // we will turn any newlines we find into spaces if ( fromBuff[i] == '\n' ) toBuffer[j++] = ' '; else { // not fond of carriage returns; throw them out. while (fromBuff[i] == '\r') i++; toBuffer[j++] = fromBuff[i]; } } } toBuffer[j] = '\0'; return toBuffer; } ////////////////////////////////////////////////////////////////////////////// // encode_password // converts the password to use the %## sequence so that special characters // in the password don't cause problems with the URL. (It also makes the // password a little more hidden on the disk, but that is barely worth // mentioning) ////////////////////////////////////////////////////////////////////////////// void encode_password( char *dest, const char *src ) { int i, j; *dest = '\0'; for (i = 0, j = 0; src[i] != '\0'; i++) j += sprintf(&dest[j], "%%%2X", tolower(src[i])); } void decode_password( char *dest, const char *src ) { int i, j; int c, t; *dest = '\0'; for(i = 0, j = 0; src[i] != '\0'; i++, j++) { if (src[i] == '%') { c = 0; t = src[i+1]; if (t >= '0' && t <= '9') c += t - '0'; else if (t >= 'a' && t <= 'f') c += t - 'a' + 10; else if (t >= 'A' && t <= 'F') c += t - 'A' + 10; else { dest[j] = src[i]; continue; } c *= 16; t = src[i+2]; if (t >= '0' && t <= '9') c += t - '0'; else if (t >= 'a' && t <= 'f') c += t - 'a' + 10; else if (t >= 'A' && t <= 'F') c += t - 'A' + 10; else { dest[j] = src[i]; continue; } dest[j] = c; i += 2; } else dest[j] = src[i]; } dest[j] = '\0'; } // Lifted this one out of lazyness // This is not particularly fast but it should do. char *stristr(const char *haystack, const char *needle) { char *pptr, *sptr, *start; uint slen, plen; for (start = (char *)haystack, pptr = (char *)needle, slen = strlen(haystack), plen = strlen(needle); slen >= plen; start++, slen--) { /* find start of pattern in string */ while (toupper(*start) != toupper(*needle)) { start++; slen--; /* if pattern longer than string */ if (slen < plen) return(NULL); } sptr = start; pptr = (char *)needle; while (toupper(*sptr) == toupper(*pptr)) { sptr++; pptr++; /* if end of pattern then pattern was found */ if ('\0' == *pptr) return (start); } } return(NULL); } // Encode the string S of length LENGTH to base64 format and place it // to STORE. STORE will be 0-terminated, and must point to a writable // buffer of at least 1+BASE64_LENGTH(length) bytes. void base64_encode (const char *s, char *store, int length) { /* Conversion table. */ static char tbl[64] = { 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/' }; int i; unsigned char *p = (unsigned char *)store; char *src = NULL; // s is used in triples: ensure engouh space for this if(length % 3) { int slen = length + 2; src = (char*)malloc(slen); if(src) { memset(src, 0, slen); memcpy(src, s, length); s = src; } } // Transform the 3x8 bits to 4x6 bits, as required by base64. for (i = 0; i < length; i += 3) { *p++ = tbl[s[0] >> 2]; *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; *p++ = tbl[s[2] & 0x3f]; s += 3; } // Pad the result if necessary... if (i == length + 1) *(p - 1) = '='; else if (i == length + 2) *(p - 1) = *(p - 2) = '='; // ...and zero-terminate it. *p = '\0'; if(src) free(src); } // Create the authentication header contents for the `Basic' scheme. // This is done by encoding the string `USER:PASS' in base64 and // prepending `HEADER: Basic ' to it. // **NOTE** when the function returns encstr contains the encoded string. // It MUST be freed to avoid a memory leak! void basic_authentication_encode (const char *user, const char *passwd, char **encstr) { char *t1, *t2; int len1 = strlen (user) + 1 + strlen (passwd); int len2 = BASE64_LENGTH (len1); t1 = (char *)malloc(len1 + 1); sprintf (t1, "%s:%s", user, passwd); t2 = (char *)malloc(1 + len2); base64_encode (t1, t2, len1); *encstr = (char *)malloc(len2 + 9); sprintf (*encstr, "Basic %s", t2); free(t1); free(t2); } FopenW::FopenW(const char *file) { static const char ext[] = ".new"; fp = NULL; real_name = file; temp_name = new char[strlen(file) + sizeof(ext)]; if(!temp_name) return; strcpy(temp_name, file); strcat(temp_name, ext); fp = fopen(temp_name, "w"); } int FopenW::close() { int ret = -1; if(fp) ret = fclose(fp); if(temp_name) { if(ret == 0 && real_name) ret = rename(temp_name, real_name); delete[] temp_name; } fp = NULL; real_name = NULL; temp_name = NULL; return ret; }