#include "Socket.h" #include #include // required for SHGetSpecialFolderPath() #include #include #include #include #include #pragma comment(lib, "Shell32.lib") using namespace std; // used by to do case-insensitive comparison of keys struct classcomp { bool operator() (const string& lhs, const string& rhs) const { return stricmp(lhs.c_str(),rhs.c_str()) < 0; } }; // required for SHGetSpecialFolderPath() char buf[MAX_PATH] = {0}; // maximum number of ip addresses that can be sent // to www.stopforumspam.com at one time. const int MaxCount = 15; // extract ip address from a string in the form "1.1.1.1" string finditem(string line, string s, int pos1) { int pos2; // find end of text " by location the '>' character for(; line[pos1] != '>'; pos1++) ; // now find "" pos2= line.find(s); // cut out what's inbetween and line = line.substr(pos1+1,pos2-pos1-1); return line; } // write final results to data file. void save(ofstream& out, map& gooditems) { map::iterator it = gooditems.begin(); for(; it != gooditems.end(); it++) { out << it->first << '\t' << it->second << '\n'; } } // optional parameter to main() is the input filename, which may NOT contain // path. Files are expected to be located in "Libraries/Documents" folder. int main(int argc, char* argv[]) { char* filename = NULL; map items; map gooditems; string line; if( argc == 2) filename = argv[1]; else filename = "registrations.txt"; // get full path to libraries/Documents folder BOOL b = SHGetSpecialFolderPath(0,buf,CSIDL_MYDOCUMENTS,0); // open both input and output files string fname = buf; fname += "//"; fname += filename; ifstream in(fname.c_str()); if( !in.is_open() ) { cout << "Can't open file " << filename << '\n'; return 1; } fname = buf; fname += "\\spam.txt"; ofstream out(fname.c_str()); if( !out.is_open() ) { cout << "Can not open output file\n"; return 1; } string uname,email,ip,s1,s2,s3; // read all the inputfile into vector. The input file consists of six tab deliminated columns // user name, email address, ip address, and three more columns that we don't use. The data // is derived from vBulletin's admin control panel Search Users Waiting Moderation. Just highlight // the list, copy to clipboard, past into Notepad, then write to a file in Libraries/Documents folder. while( getline(in,uname,'\t') ) //in >> uname >> email >> ip >> s1 >> s2 >> s3 ) { getline(in,email,'\t'); getline(in,ip,'\t'); getline(in,line); items[ip] = uname; } in.close(); map::iterator it = items.begin(); size_t pos; // Send the IP addresses to wwsw.stopforumspam.com who will return the number of times // the ip has been reported for spamming. Ips can be batch processed, a maximum of 15 // IPs batch processed at a time. The socket is closed after each call, so we have to // reopen the socket every time we make a request. // // Requests are in HTM format, such as // GET /api?ip[] = 111.111&ip[]=222.222.222.222&ip{}=333.333.333.333, etc for up to 15 addresses // while( it != items.end() ) { string cmd = "GET /api?"; int counter = 0; do { cmd += "ip[]=" + it->first + "&"; it++;7 counter++; } while( it != items.end() && counter < MaxCount); if(cmd[cmd.length()-1] == '&') cmd = cmd.substr(0,cmd.length()-1); SocketClient s("www.stopforumspam.com", 80); s.SendLine(cmd.c_str()); // stopforumspam.com is going to send back a whole bunch of worthless stuff // all we want is ipaddress and number times // If the value is 0 that means the ip has NOT been reported for // spamming, and it will be saved in the output file that this program creates. while (1) { string l = s.ReceiveLine(); if (l.empty()) break; //out << l << '\n'; if( (pos = l.find("")) != string::npos) { ip = finditem(l,"",pos); uname = items[ip]; } if( l.find("0") != std::string::npos) { cout << uname << '\t' << ip << '\n'; // we want the gooditems list to be sorted by username instead // of ip, so uname is used as the key. We already know the ip // is unuque in the file, so by definition the uname will also be // unique. gooditems[uname] = ip; } } } save(out, gooditems); }