diff --git a/3m.cpp b/3m.cpp index 4681cbb..21d9f16 100644 --- a/3m.cpp +++ b/3m.cpp @@ -13,8 +13,7 @@ #include using namespace std; -int socdesc; // Socket descriptor -string homedir, errmsg, req; // Home directory, error message, request +string homedir; // Home directory struct modlistdata { string name; @@ -37,6 +36,21 @@ string repotype; string repoaddr; }; +struct modlist { +string name; +vector rmodinfos; +}; + +string strgetline(string *str, int* erased) { +string line = ""; +for(int i = 0; (*str)[i] != '\n'; i++) { +line += (*str)[i]; +} +*str.erase(0, i); +*erased = i; +return line; +} + void *get_in_addr(sockaddr *sa) { // IP Address obtaining by protocol if(sa->sa_family == AF_INET) { return &(((sockaddr_in*)sa) -> sin_addr); @@ -219,18 +233,15 @@ while(!rmfile.eof()) { return 0; } -int parsermodlist(vector *rmodlist, string mfn) { -ifstream modlist(mfn.c_str()); +int parsermodlist(vector *rmodlist, string modlist, int size) { vector tmpv = *rmodlist; -if(!modlist) { - cerr << "Modlist parse error: Cannot open modlist file for reading." << endl; -} string action = "detect"; rmodlistdata tmprmld; -while(!modlist.eof()) { - string line; - modlist >> line; - if(modlist) { +for(int i = 0; i < size; i++) { + string line = ""; + int erased; + line = strgetline(&modlist, &erased); + size -= erased; if(action == "detect") { if(line[0] == '{') { string name = ""; @@ -306,22 +317,14 @@ while(!modlist.eof()) { return 0; } -int parsemodinfo(rmodinfo *mis, string mfn) { -ifstream modinfo(mfn.c_str()); +int parsemodinfo(rmodinfo *mis, string modinfo, int size) { rmodinfo tmp = *mis; -if(!modinfo) { - cerr << "Modinfo parse error: Cannot open modinfo file for reading." << endl; -} string action = "detect"; -while(!modinfo.eof()) { +for(int i = 0; i < size; i++) { string line = ""; - char ch; - modinfo.get(ch); - while(ch != '\n') { - line += ch; - modinfo.get(ch); - } - if(modinfo) { + int erased; + line = strgetline(&modinfo, &erased); + size -= erased; if(action == "detect") { if(line[0] == '{') { string name = ""; @@ -422,12 +425,375 @@ while(!modinfo.eof()) { return 0; } +int getmodinfo(rmodlistdata mld, rmodinfo *rmi) { +int remote; +int yes=1; +int status; + char caddr[INET6_ADDRSTRLEN]; + char rcvbuf[1000000]; + addrinfo hints; + addrinfo *servinfo, *p; + cout << "get_modinfo: Trying to get modinfo for: " << mld.name << endl; + cout << "get_modinfo: Connecting to: " << mld.server << endl; + memset(&hints, 0, sizeof(hints)); // We do not want any trash here... + hints.ai_family = AF_UNSPEC; // Make it IPv4 or IPv6 - which one fits. + hints.ai_socktype = SOCK_STREAM; // HTTP works on TCP, right? + if((status = getaddrinfo(mld.server, "http", &hints, &servinfo)) != 0) { // Trying to get servinfo - server network address etc. + cerr << "Failed to connect to the server: " << gai_strerror(status) << endl; + return 1; // 1 means GAI failed + } + for(p = servinfo; p != NULL; p = p->ai_next) { // For every GAI result try to create a socket, set socket options and, finally, connect + remote = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); + if(remote == -1) { + cerr << "Failed to create socket: " << strerror(errno) << endl; + } + if((setsockopt(remote, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)) { + cerr << "Failed to set socket options: " << strerror(errno) << endl; + } + status = connect(remote, servinfo->ai_addr, servinfo->ai_addrlen); + if(status == -1) { + cerr << "Could not connect to this address: " << strerror(errno) << endl; + continue; + } + break; + } + if(p == NULL) { + cerr << "Could not connect to the server: " << strerror(errno) << endl; + return 2; // 2 means connecting failed + } + inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), caddr, sizeof(caddr)); + freeaddrinfo(servinfo); + cout << "Connection to " << caddr << " has been successfully established!" << endl; + cout << "Sending HTTP GET request..." << endl; + string req = ""; + stringstream sreq; + sreq << "GET " << mld.modinfo << " HTTP/1.0\n\n"; + req = sreq.str(); + status = send(remote, req.c_str(), req.length(), 0); + if(status == -1) { + cerr << "Could not send HTTP GET request: " << strerror(errno) << endl; + return 3; // 3 means send failed + } + cout << status << " bytes sent" << endl; + cout << "Receiving modlist..." << endl; + status = recv(remote, &rcvbuf, 1000000, 0); + if(status == -1) { + cerr << "Could not receive modlist: " << strerror(errno) << endl; + return 4; // 4 means recv failed + } + string protocol; + int iter; + for(int i=0; i<8;i++) { + protocol += rcvbuf[i]; + iter = i; + } + string response; + for(int i=9; rcvbuf[i] != '\n'; i++) { + response += rcvbuf[i]; + iter = i; + } + string timestamp; + iter += 7; + for(int i=iter+1; rcvbuf[i] != '\n'; i++) { + timestamp += rcvbuf[i]; + iter = i; + } + string server; + iter += 9; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + server += rcvbuf[i]; + iter = i; + } + string addinfo; + for(int i = iter+1; rcvbuf[i+1] != 'C' || rcvbuf[i+2] != 'o' || rcvbuf[i+3] != 'n'; i++) { + addinfo += rcvbuf[i]; + iter = i; + } + string cl; + if(rcvbuf[iter+5] == 't') { + iter += 16; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + cl += rcvbuf[i]; + iter = i; + } + } else { + cl = ""; + } + string connection; + iter += 13; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + connection += rcvbuf[i]; + iter = i; + } + string ct; + iter += 15; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + ct += rcvbuf[i]; + iter = i; + } + string paddinfo; + if(rcvbuf[iter+1] != '\n' || rcvbuf[iter+2] != '\r' || rcvbuf[iter+3] != '\n') { + for(int i = iter+1; rcvbuf[i+1] != '\n' || rcvbuf[i+2] != '\r' || rcvbuf[i+3] != '\n';i++) { + paddinfo += rcvbuf[i]; + iter = i; + } + } else { + paddinfo = ""; + } + string content; + iter += 3; + int recvcon=0; + for(int i = iter+1; rcvbuf[i] != '\000'; i++) { + content += rcvbuf[i]; + iter = i; + recvcon++; + } + if(response[0] != '2' || response[1] != '0' || response[2] != '0' || response[4] != 'O' || response[5] != 'K') { + cerr << "HTTP Error! Response: " << response << endl; + return 5; // 5 means HTTP Error + } + if(cl != "") { + int icl; + icl = atoi(cl.c_str()); + while(recvcon < icl) { + for(int i=0; i<1000000; i++) { + rcvbuf[i] = NULL; + } + status = recv(remote, &rcvbuf, 1000000, 0); + if(status == -1) { + cerr << "Could not receive modlist: " << strerror(errno) << endl; + return 4; // 4 means recv failed + } + cout << status << " bytes received" << endl; + for(int i = iter+1; rcvbuf[i] != '\000'; i++) { + content += rcvbuf[i]; + iter = i; + recvcon++; + } + } + } + close(remote); + cout << "Received modlist! Starting modlist parser..." << endl; + modlist tmp; + + status = parsemodinfo(&tmp, content, recvcon); + if(status == 1) { + cout << "Modlist parse error!" << endl; + return 6; // 6 means parse error + } + *rmi = tmp; + return 0; // 0 means all OK +} + +int getmodlist(modlist *ml, modlistdata mld) { +int remote; +int yes=1; +int status; + char caddr[INET6_ADDRSTRLEN]; + char rcvbuf[1000000]; + addrinfo hints; + addrinfo *servinfo, *p; + cout << "get_modinfo: Trying to get modlist: " << mld.name << endl; + cout << "get_modinfo: Connecting to: " << mld.server << endl; + memset(&hints, 0, sizeof(hints)); // We do not want any trash here... + hints.ai_family = AF_UNSPEC; // Make it IPv4 or IPv6 - which one fits. + hints.ai_socktype = SOCK_STREAM; // HTTP works on TCP, right? + if((status = getaddrinfo(mld.server, "http", &hints, &servinfo)) != 0) { // Trying to get servinfo - server network address etc. + cerr << "Failed to connect to the server: " << gai_strerror(status) << endl; + return 1; // 1 means GAI failed + } + for(p = servinfo; p != NULL; p = p->ai_next) { // For every GAI result try to create a socket, set socket options and, finally, connect + remote = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); + if(remote == -1) { + cerr << "Failed to create socket: " << strerror(errno) << endl; + } + if((setsockopt(remote, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)) { + cerr << "Failed to set socket options: " << strerror(errno) << endl; + } + status = connect(remote, servinfo->ai_addr, servinfo->ai_addrlen); + if(status == -1) { + cerr << "Could not connect to this address: " << strerror(errno) << endl; + continue; + } + break; + } + if(p == NULL) { + cerr << "Could not connect to the server: " << strerror(errno) << endl; + return 2; // 2 means connecting failed + } + inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), caddr, sizeof(caddr)); + freeaddrinfo(servinfo); + cout << "Connection to " << caddr << " has been successfully established!" << endl; + cout << "Sending HTTP GET request..." << endl; + string req = ""; + stringstream sreq; + sreq << "GET " << mld.path << " HTTP/1.0\n\n"; + req = sreq.str(); + status = send(remote, req.c_str(), req.length(), 0); + if(status == -1) { + cerr << "Could not send HTTP GET request: " << strerror(errno) << endl; + return 3; // 3 means send failed + } + cout << status << " bytes sent" << endl; + cout << "Receiving modinfo..." << endl; + status = recv(remote, &rcvbuf, 1000000, 0); + if(status == -1) { + cerr << "Could not receive modinfo: " << strerror(errno) << endl; + return 4; // 4 means recv failed + } + string protocol; + int iter; + for(int i=0; i<8;i++) { + protocol += rcvbuf[i]; + iter = i; + } + string response; + for(int i=9; rcvbuf[i] != '\n'; i++) { + response += rcvbuf[i]; + iter = i; + } + string timestamp; + iter += 7; + for(int i=iter+1; rcvbuf[i] != '\n'; i++) { + timestamp += rcvbuf[i]; + iter = i; + } + string server; + iter += 9; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + server += rcvbuf[i]; + iter = i; + } + string addinfo; + for(int i = iter+1; rcvbuf[i+1] != 'C' || rcvbuf[i+2] != 'o' || rcvbuf[i+3] != 'n'; i++) { + addinfo += rcvbuf[i]; + iter = i; + } + string cl; + if(rcvbuf[iter+5] == 't') { + iter += 16; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + cl += rcvbuf[i]; + iter = i; + } + } else { + cl = ""; + } + string connection; + iter += 13; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + connection += rcvbuf[i]; + iter = i; + } + string ct; + iter += 15; + for(int i = iter+1; rcvbuf[i] != '\n'; i++) { + ct += rcvbuf[i]; + iter = i; + } + string paddinfo; + if(rcvbuf[iter+1] != '\n' || rcvbuf[iter+2] != '\r' || rcvbuf[iter+3] != '\n') { + for(int i = iter+1; rcvbuf[i+1] != '\n' || rcvbuf[i+2] != '\r' || rcvbuf[i+3] != '\n';i++) { + paddinfo += rcvbuf[i]; + iter = i; + } + } else { + paddinfo = ""; + } + string content; + iter += 3; + int recvcon=0; + for(int i = iter+1; rcvbuf[i] != '\000'; i++) { + content += rcvbuf[i]; + iter = i; + recvcon++; + } + if(response[0] != '2' || response[1] != '0' || response[2] != '0' || response[4] != 'O' || response[5] != 'K') { + cerr << "HTTP Error! Response: " << response << endl; + return 5; // 5 means HTTP Error + } + if(cl != "") { + int icl; + icl = atoi(cl.c_str()); + while(recvcon < icl) { + for(int i=0; i<1000000; i++) { + rcvbuf[i] = NULL; + } + status = recv(remote, &rcvbuf, 1000000, 0); + if(status == -1) { + cerr << "Could not receive modinfo: " << strerror(errno) << endl; + return 4; // 4 means recv failed + } + cout << status << " bytes received" << endl; + for(int i = iter+1; rcvbuf[i] != '\000'; i++) { + content += rcvbuf[i]; + iter = i; + recvcon++; + } + } + } + close(remote); + cout << "Received modinfo! Starting modinfo parser..." << endl; + modlist tmp; + vector vtmp; + status = parsemodlist(&vtmp, content, recvcon); + if(status == 1) { + cout << "Modlist parse error!" << endl; + return 6; // 6 means parse error + } + tmp.name = mld.name; + for(int i = 0; i < vtmp.size(); i++) { + rmodinfo rmi; + status = getmodinfo(vtmp[i], &rmi); + if(status != 0) { + cerr << "Getmodinfo error: " << status << endl; + } else { + tmp.rmodinfos.push_back(rmi); + } + } + *ml = tmp; + return 0; // 0 means all OK +} + +int writelocalmodlist(vector mlv, string lmlfn) { + ifstream lml(lmlfn.c_str()); + if(!lml) { + cout << "Error: Cannot open local modlist file for writing!" << endl; + return 1; // 1 means file write error + } + for(int i = 0; i < mlv.size(); i++) { + for(int j = 0; j < mlv[i].rmodinfos.size(); j++) { + lml << "{" << mlv[i].rmodinfos[j].name << "}" << endl; + lml << "[rmodlist]" << endl; + lml << mlv[i].name << endl; + lml << "[description]" << endl; + lml << mlv[i].rmodinfos[j].description << endl; + lml << "[release]" << endl; + lml << mlv[i].rmodinfos[j].release << endl; + lml << "[deps]" << endl; + for(int k = 0; k < mlv[i].rmodinfos[j].deps.size(); k++) { + lml << mlv[i].rmodinfos[j].deps[k] << endl; + } + lml << "[depsend]" << endl; + lml << "[repotype]" << endl; + lml << mlv[i].rmodinfos[j].repotype << endl; + lml << "[repoaddr]" << endl; + lml << mlv[i].rmodinfos[j].repoaddr << endl; + lml << "{end}" << endl; + } + } + lml.close(); + return 0; // 0 means all OK. +} + int main(int argc, char **argv) { homedir = getenv("HOME"); -string config; -stringstream sconfig; +string config, modlistsfn; +stringstream sconfig, smodlistsfn; sconfig << homedir << "/.3m/config"; +smodlistsfn << homedir << "/.3m/remote_modlists"; config = sconfig.str(); +modlistsfn = smodlistsfn.str(); int ps; string localrepo, localml, localri; if(argc < 2 || argv[1][0] != '-') { @@ -460,7 +826,33 @@ cout << "DEBUG: localml: " << localml << endl; cout << "DEBUG: localri: " << localri << endl; //---DEBUG END--- if(argv[1][1] == 'S') { - + cout << "Syncing local modlist with information from remote modlists and modinfos..." << endl; + cout << "Parsing remote modlist list..." << endl; + vector mldv; + int ret; + ret = parsemodlists(&mldv, modlistsfn); + if(ret == 1) { + cerr << "Remote modlist list parse error! Aborting..." << endl; + return EXIT_FAILURE; + } + vector mlv; + modlist tmp; + for(int i = 0; i < mldv.size(); i++) { + cout << "Getting modlist: " << mldv[i].name << endl; + ret = getmodlist(&tmp, mldv[i]); + if(ret != 0) { + cerr << "Error in getting modlist: " << mldv[i].name << endl; + continue; + } + mlv.push_back(tmp); + } + cout << "Got all modlists and modinfos, generating local modlist..." << endl; + ret = writelocalmodlist(mlv, localml); + if(ret == 1) { + cerr << "Local modlist write error! Aborting..." << endl; + return EXIT_FAILURE; + } + cout << "Sync finished successfully!" << endl; } else { cout << "No such action: " << argv[1] << endl << "Usage: " << argv[0] << " [-S/I/R/Q/h/v] [options] modname1 modname2 ..." << endl; }