xml_manager.cpp

00001 /* 00002 $Id: xml__manager_8cpp-source.html,v 1.1 2004/10/05 21:12:03 mentat Exp $ 00003 00004 GNU Messenger - The secure instant messenger 00005 00006 Copyright (C) 2003-2004 Jesse Lovelace <jesse at aslogicsys dot com> 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00021 */ 00022 00023 #include "gm/xml_manager.h" 00024 #include "gm/contact_manager.h" 00025 #include "gm/settings_manager.h" 00026 #include "gm/cryptography.h" 00027 00033 #include "sys/stat.h" 00034 00035 namespace GNUMessenger { 00036 00037 string XMLManager::m_directory = ""; 00038 00039 XMLManager::XMLManager(const string& directory) 00040 : m_isOnline(false) 00041 { 00042 // set initial user directory to whatever is passed to constructor 00043 setDirectory(directory); 00044 } 00045 00046 XMLManager::~XMLManager() 00047 { 00048 } 00049 00050 bool XMLManager::logout() 00051 { 00052 if (!m_isOnline) 00053 return false; 00054 00055 // save data 00056 commit(); 00057 00058 // set status to offline 00059 m_isOnline = false; 00060 00061 // set the config to a empty xml 00062 XMLNode empty; 00063 m_xml = empty; 00064 00065 // resize the disk password to zero length 00066 m_diskPass.wipe(); 00067 00068 // erase old file name 00069 m_filename.clear(); 00070 00071 return true; 00072 00073 } 00074 00075 bool XMLManager::setDirectory(const string& dir) 00076 { 00077 if (dir.empty()) { 00078 LOG_DEBUG("Dir is empty."); 00079 m_directory.clear(); 00080 return true; 00081 } 00082 00083 if (!isDirectory(dir)) { 00084 LOG_DEBUG("Dir is not a directory."); 00085 return false; 00086 } 00087 00088 m_directory = dir; 00089 00090 if ( (dir[dir.length() - 1] != '\\') && 00091 (dir[dir.length() -1] != '/')) { 00092 m_directory += '/'; 00093 } 00094 00095 return true; 00096 } 00097 00098 bool XMLManager::createNew(const string& username, const VBuffer &password) 00099 { 00100 // if username exists, return false 00101 if (exists(username)) 00102 return false; 00103 00104 if (m_isOnline) 00105 logout(); 00106 00107 // create a new file to hold user data 00108 m_filename = getFileName(username); 00109 00110 // hash the user's password to use as file key 00111 m_diskPass = CryptoManager::hash(password, CryptDefines::SHA_384); 00112 00113 // set up initial values in the xml node 00114 m_xml.setName("config").setProperty("username", username); 00115 00116 m_settingsManager.reset(new SettingsManager(m_xml)); 00117 m_contactManager.reset(new ContactManager(m_xml)); 00118 00119 // set status to online - user logged in 00120 m_isOnline = true; 00121 00122 // do initial save to disk 00123 commit(); 00124 00125 return true; 00126 00127 } 00128 00129 bool XMLManager::login(const string & username, const VBuffer &password) 00130 { 00131 // returns false if user does not exist 00132 if (!exists(username)) 00133 return false; 00134 00135 if (m_isOnline) 00136 logout(); 00137 00138 m_filename = getFileName(username); 00139 00140 m_diskPass = CryptoManager::hash(password, CryptDefines::SHA_384); 00141 00142 #if 0 00143 // plain text read in of config for testing 00144 ifstream in; 00145 string tmp, inbound; 00146 in.open("test.xml"); 00147 while (getline(in, tmp)) 00148 inbound += tmp; 00149 00150 *m_config << inbound; 00151 #endif 00152 00153 try { 00154 00155 m_xml << CryptoManager::decryptFile(m_directory + m_filename, m_diskPass); 00156 } catch(CryptoManager::InvalidPassword &e) 00157 { 00158 LOG_THROW(e.what(), PasswordError); 00159 } catch(CryptoManager::AuthFailed &e) 00160 { 00161 LOG_THROW(e.what(), AuthError); 00162 } catch(CryptoManager::IOError &e) 00163 { 00164 LOG_THROW(e.what(), DiskError); 00165 } 00166 00167 m_settingsManager.reset(new SettingsManager(m_xml)); 00168 m_contactManager.reset(new ContactManager(m_xml)); 00169 00170 m_isOnline = true; 00171 00172 return true; 00173 00174 } 00175 00176 bool 00177 XMLManager::search(const string& toFind, const string& findType, XMLNode& parentNode, XMLNode& returnNode) 00178 { 00179 unsigned int iter; 00180 for (iter = 1; iter <= parentNode.numChildren(findType); iter++) 00181 { 00182 if (parentNode.child(findType, iter).property("name") == toFind) 00183 { 00184 returnNode = parentNode.child(findType, iter); 00185 return true; 00186 } 00187 } 00188 00189 /* search through folders */ 00190 for (iter = 0; iter < parentNode.children().size(); iter++) 00191 { 00192 if (search(toFind, findType, parentNode.children()[iter], returnNode)) 00193 return true; 00194 } 00195 00196 return false; 00197 } 00198 00199 bool 00200 XMLManager::baseSearch(const string& toFind, const string& findType, XMLNode& parentNode, XMLNode& returnNode, unsigned int& num) 00201 { 00202 /* search through things of type findType */ 00203 00204 for (unsigned int iter2 = 1; iter2 <= parentNode.numChildren(findType); iter2++) 00205 { 00206 if (parentNode.child(findType, iter2).property("name") == toFind) 00207 { 00208 num = iter2; 00209 returnNode = parentNode; 00210 return true; 00211 } 00212 } 00213 00214 /* search through folders */ 00215 for (unsigned int iter = 0; iter < parentNode.children().size(); iter++) 00216 { 00217 if (baseSearch(toFind, findType, parentNode.children()[iter], returnNode, num)) 00218 00219 return true; 00220 } 00221 00222 return false; 00223 } 00224 00225 unsigned int 00226 XMLManager::tagCount(const string& findType, const XMLNode& parentNode) 00227 { 00228 /* search through things of type findType */ 00229 00230 unsigned int levelCount(parentNode.numChildren(findType)); 00231 00232 /* search through folders */ 00233 for (unsigned int iter = 0; iter < parentNode.const_children().size(); iter++) 00234 { 00235 levelCount += tagCount(findType, parentNode.const_children()[iter]); 00236 } 00237 00238 return levelCount; 00239 } 00240 00241 void XMLManager::getAllTags(const string& findType, XMLNode& parentNode, vector<XMLNode> &result_vector) 00242 { 00243 for (unsigned int iter2 = 1; iter2 <= parentNode.numChildren(findType); iter2++) 00244 { 00245 result_vector.push_back(parentNode.child(findType, iter2)); 00246 } 00247 00248 /* search through folders */ 00249 for (unsigned int iter = 0; iter < parentNode.children().size(); iter++) 00250 { 00251 getAllTags(findType, parentNode.children()[iter], result_vector); 00252 00253 } 00254 } 00255 00256 string XMLManager::printTree(const XMLNode& base) 00257 { 00258 return base; 00259 } 00260 00261 bool XMLManager::commit() 00262 { 00263 // if user is not logged in, then cannot commit to disk 00264 if (!m_isOnline) 00265 { 00266 LOG_ERROR("Cannot Commit to file while not logged in."); 00267 return false; 00268 } 00269 00270 // add xml encoding information for expat 00271 string data("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); 00272 00273 // convert xmlnode to a string 00274 data += string(m_xml); 00275 00276 // try to encrypt to disk 00277 try 00278 { 00279 CryptoManager::encryptFile(m_directory + m_filename, m_diskPass, data.c_str()); 00280 } 00281 catch (CryptoManager::IOError &e) 00282 { 00283 LOG_THROW(e.what(), DiskError); 00284 return false; 00285 } 00286 00287 //#ifdef _DEBUG 00288 // write out debug xml 00289 ofstream out; 00290 string dir = m_directory + string("test.xml"); 00291 out.open(dir.c_str()); 00292 out << data; 00293 //#endif 00294 00295 return true; 00296 } 00297 00298 string XMLManager::encode(const string & inbound) 00299 { 00300 00301 string outbound; 00302 unsigned int i(0); 00303 00304 // first pass - remove # and & and ; 00305 for (i = 0; i < inbound.size(); i++) 00306 { 00307 switch (inbound[i]) 00308 { 00309 case('#'): outbound += "&#35;"; break; 00310 case('&'): outbound += "&#38;"; break; 00311 case(';'): outbound += "&#59;"; break; 00312 case('\''): outbound += "&#39;"; break; // i dont know why i'm doing this one 00313 case('\"'): outbound += "&#34;"; break; 00314 default: outbound += inbound[i]; 00315 } 00316 } 00317 00318 return outbound; 00319 } 00320 00321 string XMLManager::decode(const string & inbound) 00322 { 00323 00324 string outbound; 00325 string code; 00326 00327 int STATE(0); 00328 unsigned int i(0); 00329 /* 00330 States: 00331 0 - not in HTML code 00332 1 - in HTML code 00333 2 - found ending ';' in HTML code 00334 */ 00335 for (i = 0; i < inbound.size(); i++) 00336 { 00337 switch (inbound[i]) 00338 { 00339 case('&'): STATE = 1; code = '&'; break; 00340 case(';'): STATE = 2; code += ';'; break; 00341 default: 00342 { 00343 if ( STATE > 0 ) 00344 code += inbound[i]; 00345 else 00346 outbound += inbound[i]; 00347 } 00348 } 00349 if (STATE == 2) 00350 { 00351 STATE = 0; 00352 if (code == "&#35;") 00353 outbound += '#'; 00354 if (code == "&#38;") 00355 outbound += '&'; 00356 if (code == "&#59;") 00357 outbound +=';'; 00358 if (code == "&#39;") 00359 outbound += '\''; 00360 if (code == "&#34;") 00361 outbound += '\"'; 00362 } 00363 } 00364 00365 return outbound; 00366 00367 00368 } 00369 00370 bool 00371 XMLManager::exists(const string& username) 00372 { 00373 string toOpen; 00374 toOpen += m_directory; 00375 toOpen += CryptoManager::encode(username, CryptDefines::Base32); // file name 00376 toOpen += ".gm"; 00377 00378 struct stat my_stat; 00379 return (stat(toOpen.c_str(), &my_stat) == 0); 00380 00381 #if 0 00382 ifstream in; 00383 in.open(toOpen.c_str()); 00384 00385 if (in.fail() || in.bad()) 00386 { 00387 return false; 00388 } 00389 return true; 00390 #endif 00391 } 00392 00393 00394 bool XMLManager::isDirectory(const string& dirname) 00395 { 00396 struct stat my_stat; 00397 if (stat(dirname.c_str(), &my_stat) != 0) 00398 return false; 00399 return ((my_stat.st_mode & S_IFDIR) != 0); 00400 } 00401 00402 string XMLManager::getFileName(const string& username) const 00403 { 00404 return CryptoManager::encode(username, CryptDefines::Base32) + string(".gm"); 00405 } 00406 00407 bool 00408 XMLManager::setPassword(const VBuffer& password) 00409 { 00410 00411 if (!m_isOnline) 00412 return false; 00413 00414 // set new password 00415 m_diskPass = CryptoManager::hash(password, CryptDefines::SHA_384); 00416 00417 // save with new password 00418 commit(); 00419 00420 return true; 00421 00422 } 00423 00424 string 00425 XMLManager::getLogin() const 00426 { 00427 if (!m_isOnline) 00428 return ""; 00429 00430 return m_xml.property("username"); 00431 } 00432 00433 } // !GNUMessenger 00434 00435 /* 00436 ----- 00437 $Log: xml_manager.cpp,v $ 00438 Revision 1.1.1.1 2004/10/03 06:17:37 mentat 00439 Initial re-import. 00440 00441 Revision 1.4 2003/04/20 19:29:51 mentat 00442 Commiting code, trying to fix reference update bug. 00443 00444 Revision 1.3 2003/04/13 18:43:58 mentat 00445 Heavy commits. 00446 00447 Revision 1.2 2003/04/09 21:19:18 mentat 00448 Adding new source. 00449 00450 Revision 1.1 2003/03/02 16:19:05 mentat 00451 Importing new sources. 00452 00453 00454 */

Generated on Tue Oct 5 14:41:47 2004 for GNU Messenger by doxygen 1.3.8