diff --git a/3m.h b/3m.h index 908ed16..12126c5 100644 --- a/3m.h +++ b/3m.h @@ -10,6 +10,8 @@ #include "ModListList.h" #include "RepositoryModDescription.h" #include "LocalModList.h" +#include "RepositoryModDescription.h" +#include "NetSocket++/NetSocketPP.h" /// \file 3m.h /// \brief A common header for 3m and definitions of helper functions. /// \author Phitherek_ @@ -34,5 +36,18 @@ std::string strip_endl(std::string s) { } return s; } + +/// \fn std::string strgetline(std::string *str) +/// \brief A function that gets line from the multiline string and erases it from this string. +/// \param[in,out] str A pointer to the string to get line from. The line is erased from the string. +/// \return Line from the string. +std::string strgetline(std::string *str) { +std::string line = ""; +int i; +for(i = 0; (*str)[i] != '\n'; i++) { +line += (*str)[i]; +} +return line; +} } #endif diff --git a/3mExceptions.cpp b/3mExceptions.cpp index 696bc19..1330a92 100644 --- a/3mExceptions.cpp +++ b/3mExceptions.cpp @@ -41,14 +41,28 @@ const char* ParseException::what() const throw() { return msg.c_str(); } -OutOfBoundsException::OutOfBoundsException(std::string what) { +BadResponseException::BadResponseException(std::string response) { + _response = response; +} + +BadResponseException::~BadResponseException() throw() { + _response = ""; +} + +const char* BadResponseException::what() const throw() { + std::string what = "Got HTTP response: "; + what += _response; + return what.c_str(); +} + +NonEditableException::NonEditableException(std::string what) { _what = what; } -OutOfBoundsException::~OutOfBoundsException() throw() { +NonEditableException::~NonEditableException() throw() { _what = ""; } -const char* OutOfBoundsException::what() const throw() { +const char* NonEditableException::what() const throw() { return _what.c_str(); } diff --git a/3mExceptions.h b/3mExceptions.h index 974f929..a2fe902 100644 --- a/3mExceptions.h +++ b/3mExceptions.h @@ -41,17 +41,29 @@ public: const char* what() const throw(); ///< \brief A function, that returns the whole error. ///< \return Whole error message. }; -/// \class OutOfBoundsException -/// \brief An exception to be thrown when the iterator gets out of container bounds. -class OutOfBoundsException: public std::exception { +/// \class BadResponseException +/// \brief An exception to be thrown on not 200 HTTP response. +class BadResponseException: public std::exception { private: - std::string _what; + std::string _response; public: - OutOfBoundsException(std::string what); ///< \brief A constructor with parameters. - ///< \param what Error message. + OutOfBoundsException(std::string response); ///< \brief A constructor with parameters. + ///< \param response HTTP response that caused the exception. ~OutOfBoundsException() throw(); ///< A destructor, as needed by std::exception. const char* what() const throw(); ///< \brief A function returning error message. /// \return Error message. }; +/// \class NonEditableException +/// \brief An exception to be thrown when trying to write a remotely obtained, non-editable structure. +class NonEditableException: public std::exception { +private: + std::string _what; +public: + NonEditableException(std::string what); ///< \brief A constructor with parameters. + ///< \param what Error message. + ~NonEditableException() throw(); ///< A destructor, as needed by std::exception. + const char* what() const throw(); ///< \brief A function returning error message. + /// \return Error message. +}; } #endif diff --git a/ModInfo.cpp b/ModInfo.cpp new file mode 100644 index 0000000..6cbbf1d --- /dev/null +++ b/ModInfo.cpp @@ -0,0 +1,349 @@ +#include "ModInfo.h" +#include "NetSocket++/NetSocketPP.h" +#include +using namespace mmm; + +ModInfo::ModInfo() { + ModInfoDescription emptymid; + _desc = emptymid; + _edit = false; +} + +ModInfo::ModInfo(ModInfoDescription mid) { + _desc = mid; + _edit = false; + NetSocketPP::HTTPReply data; + try { + NetSocketPP::HTTPClientSocket conn(_desc.getServer(), "http", _desc.getPath()); + std::cout << "Connection to " << conn.getIP() << " successful!" << std::endl; + data = conn.getReply(); + } catch (NetSocketPP::SocketException &exc) { + std::cerr << "SocketException occured while getting remote modinfo: " << exc.what() << std::endl; + throw(exc); + } catch (NetSocketPP::NetworkException &exc) { + std::cerr << "NetworkException occured while getting remote modinfo: " << exc.what() << std::endl; + throw(exc); + } + if(data.getResponse() != "200 OK") { + throw BadResponseException(data.getResponse()); + } + std::string modinfo = data.getContent(); + std::string action = "detect"; +for(unsigned int i = 0; i < modinfo.length(); i++) { + std::string line = ""; + line = strgetline(&modinfo); + if(line[0] != NULL && line[0] != ' ' && line[0] != '\n' && line[0] != '\r') { + if(action == "detect") { + if(line[0] == '{') { + std::string name = ""; + for(unsigned int i = 1; line[i] != '}' && i < line.length(); i++) { + name += line[i]; + } + _name = name; + action = "parse"; + } else { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although { was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else if(action == "parse") { + if(line[0] == '{') { + if(line[1] == 'e' && line[2] == 'n' && line[3] == 'd' && line[4] == '}') { + action = "detect"; + } else { + std::string msg = ""; + msg += "Found "; + msg += line; + msg += " although {end} or action in [] was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else if(line[0] == '[') { + std::string tmpact = ""; + for(unsigned int i = 1; line[i] != ']' && i < line.length(); i++) { + tmpact += line[i]; + } + if(tmpact == "description" || tmpact == "release" || tmpact == "deps" || tmpact == "repotype" || tmpact == "repoaddr") { + action = tmpact; + } else { + std::string msg = ""; + msg += "Found "; + msg += tmpact; + msg += " although description/release/deps/repotype/repoaddr was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else { + std::string msg = ""; + msg += "Found "; + msg += line; + msg += " although {end} or action in [] was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else if(action == "description") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _description = line; + action = "parse"; + } + } else if(action == "release") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _release = atoi(line.c_str()); + action = "parse"; + } + } else if(action == "deps") { + if(line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string or [ was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else if(line[0] == '[') { + if(line[1] == 'd' && line[2] == 'e' && line[3] == 'p' && line[4] == 's' && line[5] == 'e' && line[6] == 'n' && line[7] == 'd' && line[8] == ']') { + if(_deps.empty()) { + _deps.push_back("none"); + } + action = "parse"; + } else { + std::string msg = ""; + msg += "Found "; + msg += line; + msg += " although string or [depsend] was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else { + _deps.push_back(line); + } + } else if(action == "repotype") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _repotype = line; + action = "parse"; + } + } else if(action == "repoaddr") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _repoaddr = line; + action = "parse"; + } + } else { + throw ParseException(_desc.getServer() + _desc.getPath(), "The program should not reach this place!"); + } +} +} +} + +ModInfo::ModInfo(std::string path) { + _edit = true; + ModInfoDescription emptymid; + _desc = emptymid; + _localPath = path; + std::ifstream modinfo(_localPath.c_str()); + if(!modinfo) { + throw FileException(_localPath, "reading", "Could not open file!"); + } + std::string action = "detect"; + while(!modinfo.eof()) { + std::string line = ""; + char c; + do { + modinfo.get(c); + if(c != '\n'); + line += c; + } while(c != '\n'); + line = strip_endl(line); + if(modinfo) { + if(line[0] != NULL && line[0] != ' ' && line[0] != '\n' && line[0] != '\r') { + if(action == "detect") { + if(line[0] == '{') { + std::string name = ""; + for(unsigned int i = 1; line[i] != '}' && i < line.length(); i++) { + name += line[i]; + } + _name = name; + action = "parse"; + } else { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although { was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else if(action == "parse") { + if(line[0] == '{') { + if(line[1] == 'e' && line[2] == 'n' && line[3] == 'd' && line[4] == '}') { + action = "detect"; + } else { + std::string msg = ""; + msg += "Found "; + msg += line; + msg += " although {end} or action in [] was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else if(line[0] == '[') { + std::string tmpact = ""; + for(unsigned int i = 1; line[i] != ']' && i < line.length(); i++) { + tmpact += line[i]; + } + if(tmpact == "description" || tmpact == "release" || tmpact == "deps" || tmpact == "repotype" || tmpact == "repoaddr") { + action = tmpact; + } else { + std::string msg = ""; + msg += "Found "; + msg += tmpact; + msg += " although description/release/deps/repotype/repoaddr was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else { + std::string msg = ""; + msg += "Found "; + msg += line; + msg += " although {end} or action in [] was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else if(action == "description") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _description = line; + action = "parse"; + } + } else if(action == "release") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _release = atoi(line.c_str()); + action = "parse"; + } + } else if(action == "deps") { + if(line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string or [ was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else if(line[0] == '[') { + if(line[1] == 'd' && line[2] == 'e' && line[3] == 'p' && line[4] == 's' && line[5] == 'e' && line[6] == 'n' && line[7] == 'd' && line[8] == ']') { + if(_deps.empty()) { + _deps.push_back("none"); + } + action = "parse"; + } else { + std::string msg = ""; + msg += "Found "; + msg += line; + msg += " although string or [depsend] was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } + } else { + _deps.push_back(line); + } + } else if(action == "repotype") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _repotype = line; + action = "parse"; + } + } else if(action == "repoaddr") { + if(line[0] == '[' || line[0] == '{') { + std::string msg = ""; + msg += "Found "; + msg += line[0]; + msg += " although string was expected."; + throw ParseException(_desc.getServer() + _desc.getPath(), msg); + } else { + _repoaddr = line; + action = "parse"; + } + } else { + throw ParseException(_desc.getServer() + _desc.getPath(), "The program should not reach this place!"); + } +} + } + } +} + +void ModInfo::setPath(std::string path) { + _edit = true; + _localPath = path; +} + +void ModInfo::write() { + if(!_edit) { + throw NonEditableException("Tried to write back remotely obtained modinfo file!"); + } + std::ofstream modinfo(_localPath.c_str()); + if(!ofstream) { + throw FileException(_localPath, "writing", "Could not open file!"); + } + modinfo << "{" << _name << "}" << std::endl << "[description]" << std::endl << _description << std::endl << "[release]" << std::endl << _release << std::endl << "[deps]" << std::endl; + if(_deps.size() == 0) { + modinfo << "none" << std::endl; + } else { + for(unsigned int i = 0; i < _deps.size(); i++) { + modinfo << _deps[i] << std::endl; + } + } + modinfo << "[depsend]" << std::endl << "[repotype]" << std::endl << _repotype << std::endl << "[repoaddr]" << std::endl << _repoaddr << std::endl << "{end}" << std::endl; + modinfo.close(); +} + +void ModInfo::releaseInc() { + _release++; +} + +void ModInfo::~ModInfo() { + ModInfoDescription emptymid; + _desc = emptymid; + _edit = false; + _localPath = ""; +} + +void ModInfo::clear() { + _name = ""; + _description = ""; + _release = 0; + _depsIterator = -1; + _depsAtEnd = true; + _repotype = ""; + _repoaddr = ""; + _deps.clear(); + ModInfoDescription emptymid; + _desc = emptymid; + _edit = false; + _localPath = ""; +} diff --git a/ModInfo.h b/ModInfo.h new file mode 100644 index 0000000..218afe3 --- /dev/null +++ b/ModInfo.h @@ -0,0 +1,37 @@ +#ifndef _MODINFO_H +#define _MODINFO_H +#include "3m.h" +#include +/// \file ModInfo.h +/// \brief A class that represents remote modinfo file. +/// \author Phitherek_ +/// \date 2013 +/// \version 0.1-pre + +/// \namespace mmm +/// \brief A global namespace for 3m. +namespace mmm { +/// \class ModInfo +/// \brief A class that represents remote modinfo file +class ModInfo: public ModDescription { +private: +ModInfoDescription _desc; +bool _edit; +std::string _localPath; +public: +ModInfo(); ///< A constructor. +ModInfo(ModInfoDescripton mid); ///< \brief A constructor from ModInfoDescription object. +///< Tries to download and parse remote modinfo file. +///< \param mid A ModInfoDescription object. +ModInfo(std::string path); ///< \brief A construtor from the path to local modinfo file. +///< It tries to open and parse local modinfo file, opening it for editing. +///< \param path A path to local modinfo file. +void setPath(std::string path); ///< \brief A function that sets local modinfo file to edit. +///< \param path A path to local modinfo file. +void write(); ///< A function that writes the changes to local modinfo file. +void releaseInc(); ///< A function that increases modinfo release. +~ModInfo(); ///< A destructor. +void clear(); ///< A function that clears the object. +}; +} +#endif diff --git a/ModInfoDescription.cpp b/ModInfoDescription.cpp index 0707e04..74189e5 100644 --- a/ModInfoDescription.cpp +++ b/ModInfoDescription.cpp @@ -36,3 +36,9 @@ _server = server; void ModInfoDescription::setPath(std::string path) { _path = path; } + +void ModInfoDescription::clear() { +_name = ""; +_server = ""; +_path = ""; +} diff --git a/ModInfoDescription.h b/ModInfoDescription.h index 9659450..26426f3 100644 --- a/ModInfoDescription.h +++ b/ModInfoDescription.h @@ -35,6 +35,7 @@ public: ///< \param server Server with modinfo. void setPath(std::string path); ///< \brief A function setting modinfo path on server. ///< \param path Modinfo path on server. + void clear(); ///< A function clearing the object. }; } #endif diff --git a/ModList.cpp b/ModList.cpp new file mode 100644 index 0000000..8fe879d --- /dev/null +++ b/ModList.cpp @@ -0,0 +1,40 @@ +#include "ModList.h" +#include "NetSocket++/NetSocketPP.h" +#include "3mExceptions.h" +using namespace mmm; + +ModList::ModList() { + ModListDescription emptymld; + _desc = emptymld; + _modinfos.clear(); + _edit = false; + _localPath = ""; + _modinfosIterator = -1; + _modinfosAtEnd = true; +} + +ModList::ModList(ModListDescription mld) { + _desc = mld; + _modinfos.clear(); + _edit = false; + _localPath = ""; + _modinforIterator = -1; + _modinfosAtEnd = false; + NetSocketPP::HTTPReply data; + try { + NetSocketPP::HTTPClientSocket conn(_desc.getServer(), "http", _desc.getPath()); + std::cout << "Connection to " << conn.getIP() << " successful!" << std::endl; + data = conn.getReply(); + } catch (NetSocketPP::SocketException &exc) { + std::cerr << "SocketException occured while getting remote modlist: " << exc.what() << std::endl; + throw(exc); + } catch (NetSocketPP::NetworkException &exc) { + std::cerr << "NetworkException occured while getting remote modlist: " << exc.what() << std::endl; + throw(exc); + } + if(data.getResponse() != "200 OK") { + throw BadResponseException(data.getResponse()); + } + std::string content = data.getContent(); + +} diff --git a/ModList.h b/ModList.h new file mode 100644 index 0000000..e7a9870 --- /dev/null +++ b/ModList.h @@ -0,0 +1,49 @@ +#ifndef _MODLIST_H +#define _MODLIST_H +#include "ModListDescription.h" +#include "ModInfoDescription.h" +#include +#include +/// \file ModList.h +/// \brief A class representing a modlist. +/// \author Phitherek_ +/// \date 2013 +/// \version 0.1-pre + +/// \namespace mmm +/// \brief A global namespace for 3m. +namespace mmm { +/// \class ModList +/// \brief A class representing a modlist. +class ModList { +private: + ModListDescription _desc; + std::vector _modinfos; + bool _edit; + std::string _localPath; + int _modinfosIterator; + bool _modinfosAtEnd; +public: + ModList(); ///< A constructor. + ModList(ModListDescription mld); ///< \brief A constructor from ModListDescription. + ///< It tries to download and parse the remote modlist file. It throws ParseException or one of NetSocket++ exceptions. + ///< \param mld A ModListDescription object. + ModList(std::string path); ///< \brief A constructor from std::string. + ///< It tries to open and parse locally stored modlist file. It throws FileException or ParseException. + ~ModList(); ///< A destructor. + ModInfoDescription getNextModInfoDescription(); ///< \brief A function that returns next ModInfoDescription from the modlist. + ///< \return Next ModInfoDescription from the modlist or empty ModInfoDescription object if at the end of modlist. + ModInfoDescription getModInfoDescriptionByName(std::string name); ///< \brief A function that searches for modinfo name and returns its ModInfoDescription. + ///< \param name Modinfo name. + ///< \return ModInfoDescription of the modinfo or empty ModInfoDescription object on failure. + void insertModInfoDescription(ModInfoDescription mid); ///< \brief A function that inserts a ModInfoDescription to the modlist. + ///< \param mid A ModInfoDescription to be inserted. + void deleteModInfoDescription(std::string name); ///< \brief A function that deletes ModInfoDescription of given name from the modlist. + ///< \param name Modinfo name. + void resetModInfoDescriptionIterator(); ///< A function that resets modlist iterator. + bool modInfoDescriptionsAtEnd(); ///< \brief A function, that returns if modlist iterator reached its end. + ///< \return True if modlist iterator reached its end, false otherwise. + void write(); ///< A function that writes modlist to local file. +}; +} +#endif diff --git a/OBJECTS b/OBJECTS index 73c42b6..e784f8b 100644 --- a/OBJECTS +++ b/OBJECTS @@ -14,4 +14,3 @@ SyncAction InstallAction UpdateAction RemoveAction -InfoAction