ldif.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       ldif.cc
00003 ///             Routines for reading and writing LDAP LDIF data.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2011, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "ldif.h"
00023 #include "record.h"
00024 #include "r_contact.h"
00025 #include "base64.h"
00026 #include <stdexcept>
00027 #include <iostream>
00028 #include <iomanip>
00029 #include <string.h>
00030 
00031 #define __DEBUG_MODE__
00032 #include "debug.h"
00033 
00034 namespace Barry {
00035 
00036 const ContactLdif::NameToFunc ContactLdif::FieldMap[] = {
00037         { "Email", "Email address",
00038                 &ContactLdif::Email, &ContactLdif::SetEmail },
00039         { "Phone", "Phone number",
00040                 &ContactLdif::Phone, &ContactLdif::SetPhone },
00041         { "Fax", "Fax number",
00042                 &ContactLdif::Fax, &ContactLdif::SetFax },
00043         { "WorkPhone", "Work phone number",
00044                 &ContactLdif::WorkPhone, &ContactLdif::SetWorkPhone },
00045         { "HomePhone", "Home phone number",
00046                 &ContactLdif::HomePhone, &ContactLdif::SetHomePhone },
00047         { "MobilePhone", "Mobile phone number",
00048                 &ContactLdif::MobilePhone, &ContactLdif::SetMobilePhone },
00049         { "Pager", "Pager number",
00050                 &ContactLdif::Pager, &ContactLdif::SetPager },
00051         { "PIN", "PIN",
00052                 &ContactLdif::PIN, &ContactLdif::SetPIN },
00053         { "FirstName", "First name",
00054                 &ContactLdif::FirstName, &ContactLdif::SetFirstName },
00055         { "LastName", "Last name",
00056                 &ContactLdif::LastName, &ContactLdif::SetLastName },
00057         { "Company", "Company name",
00058                 &ContactLdif::Company, &ContactLdif::SetCompany },
00059         { "DefaultCommunicationsMethod", "Default communications method",
00060                 &ContactLdif::DefaultCommunicationsMethod, &ContactLdif::SetDefaultCommunicationsMethod },
00061         { "WorkAddress1", "Work Address, line 1",
00062                 &ContactLdif::WorkAddress1, &ContactLdif::SetWorkAddress1 },
00063         { "WorkAddress2", "Work Address, line 2",
00064                 &ContactLdif::WorkAddress2, &ContactLdif::SetWorkAddress2 },
00065         { "WorkAddress3", "Work Address, line 3",
00066                 &ContactLdif::WorkAddress3, &ContactLdif::SetWorkAddress3 },
00067         { "WorkCity", "WorkCity",
00068                 &ContactLdif::WorkCity, &ContactLdif::SetWorkCity },
00069         { "WorkProvince", "WorkProvince / State",
00070                 &ContactLdif::WorkProvince, &ContactLdif::SetWorkProvince },
00071         { "WorkPostalCode", "Work Postal / ZIP code",
00072                 &ContactLdif::WorkPostalCode, &ContactLdif::SetWorkPostalCode },
00073         { "WorkCountry", "WorkCountry",
00074                 &ContactLdif::WorkCountry, &ContactLdif::SetWorkCountry },
00075         { "JobTitle", "Job Title",
00076                 &ContactLdif::JobTitle, &ContactLdif::SetJobTitle },
00077         { "PublicKey", "Public key",
00078                 &ContactLdif::PublicKey, &ContactLdif::SetPublicKey },
00079         { "Notes", "Notes",
00080                 &ContactLdif::Notes, &ContactLdif::SetNotes },
00081         { "Image", "Contact photo",
00082                 &ContactLdif::Image, &ContactLdif::SetImage },
00083         { "WorkPostalAddress", "Mailing Work address (includes address lines, city, province, country, and postal code)",
00084                 &ContactLdif::WorkPostalAddress, &ContactLdif::SetWorkPostalAddress },
00085         { "HomePostalAddress", "Mailing home address (includes address lines, city, province, country, and postal code)",
00086                 &ContactLdif::HomePostalAddress, &ContactLdif::SetHomePostalAddress },
00087         { "FullName", "First + Last names",
00088                 &ContactLdif::FullName, &ContactLdif::SetFullName },
00089         { "FQDN", "Fully qualified domain name",
00090                 &ContactLdif::FQDN, &ContactLdif::SetFQDN },
00091         { 0, 0, 0 }
00092 };
00093 
00094 
00095 bool ContactLdif::LdifAttribute::operator<(const LdifAttribute &other) const
00096 {
00097         // the dn attribute always comes first in LDIF output
00098         if( name == "dn" ) {
00099                 if( other.name == "dn" )
00100                         return false;   // both dn, so equal
00101                 return true;
00102         }
00103         else if( other.name == "dn" )
00104                 return false;
00105 
00106         return (order < other.order && name != other.name) ||
00107                 (order == other.order && name < other.name);
00108 }
00109 
00110 bool ContactLdif::LdifAttribute::operator==(const LdifAttribute &other) const
00111 {
00112         return name == other.name;
00113 }
00114 
00115 
00116 ///////////////////////////////////////////////////////////////////////////////
00117 // ContactLdif class
00118 
00119 ContactLdif::ContactLdif(const std::string &baseDN)
00120         : m_baseDN(baseDN)
00121 {
00122         // setup some sane defaults
00123         Map("mail", &ContactLdif::Email, &ContactLdif::SetEmail);
00124         Map("facsimileTelephoneNumber", &ContactLdif::Fax, &ContactLdif::SetFax);
00125         Map("telephoneNumber", &ContactLdif::WorkPhone, &ContactLdif::SetWorkPhone);
00126         Map("homePhone", &ContactLdif::HomePhone, &ContactLdif::SetHomePhone);
00127         Map("mobile", &ContactLdif::MobilePhone, &ContactLdif::SetMobilePhone);
00128         Map("pager", &ContactLdif::Pager, &ContactLdif::SetPager);
00129         Map("l", &ContactLdif::WorkCity, &ContactLdif::SetWorkCity);
00130         Map("st", &ContactLdif::WorkProvince, &ContactLdif::SetWorkProvince);
00131         Map("postalCode", &ContactLdif::WorkPostalCode, &ContactLdif::SetWorkPostalCode);
00132         Map("o", &ContactLdif::Company, &ContactLdif::SetCompany);
00133         Map("c", &ContactLdif::WorkCountry, &ContactLdif::SetWorkCountry);
00134         SetObjectClass("c", "country");
00135 
00136         Map("title", &ContactLdif::JobTitle, &ContactLdif::SetJobTitle);
00137         Map("dn", &ContactLdif::FQDN, &ContactLdif::SetFQDN);
00138         Map("displayName", &ContactLdif::FullName, &ContactLdif::SetFullName);
00139         Map("cn", &ContactLdif::FullName, &ContactLdif::SetFullName);
00140         Map("sn", &ContactLdif::LastName, &ContactLdif::SetLastName);
00141         Map("givenName", &ContactLdif::FirstName, &ContactLdif::SetFirstName);
00142         Map("street", &ContactLdif::WorkAddress1, &ContactLdif::SetWorkAddress1);
00143         Map("postalAddress", &ContactLdif::WorkPostalAddress, &ContactLdif::SetWorkPostalAddress);
00144         Map("homePostalAddress", &ContactLdif::HomePostalAddress, &ContactLdif::SetHomePostalAddress);
00145         Map("note", &ContactLdif::Notes, &ContactLdif::SetNotes);
00146         // FIXME - jpegPhoto looks like the only LDIF field for photo
00147         // images... it is unknown which format will come from the
00148         // BlackBerry in the Image field, so we can't guarantee
00149         // that Image will be in JPG.  This mapping can be done manually
00150         // from the btool command line with "-m jpegPhoto,Image,Image"
00151         // Reading photos from LDIF should be fine, since the BlackBerry
00152         // seems to handle most formats.
00153 //      Map("jpegPhoto", &ContactLdif::Image, &ContactLdif::SetImage);
00154 
00155         // add heuristics hooks
00156         Hook("cn", &m_cn);
00157         Hook("displayName", &m_displayName);
00158         Hook("sn", &m_sn);
00159         Hook("givenName", &m_givenName);
00160 
00161         // set default DN attribute
00162         SetDNAttr("cn");
00163 }
00164 
00165 ContactLdif::~ContactLdif()
00166 {
00167 }
00168 
00169 void ContactLdif::DoWrite(Barry::Contact &con,
00170                           const std::string &attr,
00171                           const std::string &data)
00172 {
00173         // valid?
00174         if( attr.size() == 0 || data.size() == 0 )
00175                 return;
00176 
00177         // now have attr/data pair, check hooks:
00178         HookMapType::iterator hook = m_hookMap.find(attr);
00179         if( hook != m_hookMap.end() ) {
00180                 *(hook->second) = data;
00181         }
00182 
00183         // run according to map
00184         AccessMapType::iterator acc = m_map.find(attr);
00185         if( acc != m_map.end() ) {
00186                 (this->*(acc->second.write))(con, data);
00187         }
00188 }
00189 
00190 void ContactLdif::Hook(const std::string &ldifname, std::string *var)
00191 {
00192         m_hookMap[ldifname] = var;
00193 }
00194 
00195 const ContactLdif::NameToFunc*
00196 ContactLdif::GetField(const std::string &fieldname) const
00197 {
00198         for( const NameToFunc *n = FieldMap; n->name; n++ ) {
00199                 if( fieldname == n->name )
00200                         return n;
00201         }
00202         return 0;
00203 }
00204 
00205 std::string ContactLdif::GetFieldReadName(GetFunctionType read) const
00206 {
00207         for( const NameToFunc *n = FieldMap; n->name; n++ ) {
00208                 if( read == n->read )
00209                         return n->name;
00210         }
00211         return "<unknown>";
00212 }
00213 
00214 std::string ContactLdif::GetFieldWriteName(SetFunctionType write) const
00215 {
00216         for( const NameToFunc *n = FieldMap; n->name; n++ ) {
00217                 if( write == n->write )
00218                         return n->name;
00219         }
00220         return "<unknown>";
00221 }
00222 
00223 bool ContactLdif::Map(const LdifAttribute &ldifname,
00224                       const std::string &readField,
00225                       const std::string &writeField)
00226 {
00227         const NameToFunc *read = GetField(readField);
00228         const NameToFunc *write = GetField(writeField);
00229         if( !read || !write )
00230                 return false;
00231         Map(ldifname, read->read, write->write);
00232         return true;
00233 }
00234 
00235 void ContactLdif::Map(const LdifAttribute &ldifname,
00236                       GetFunctionType read,
00237                       SetFunctionType write)
00238 {
00239         m_map[ldifname] = AccessPair(read, write);
00240 }
00241 
00242 void ContactLdif::Unmap(const LdifAttribute &ldifname)
00243 {
00244         m_map.erase(ldifname);
00245 }
00246 
00247 //
00248 // SetDNAttr
00249 //
00250 /// Sets the LDIF attribute name to use when constructing the FQDN.
00251 /// The FQDN field will take this name, and combine it with the
00252 /// baseDN from the constructor to produce a FQDN for the record.
00253 ///
00254 bool ContactLdif::SetDNAttr(const LdifAttribute &name)
00255 {
00256         // try to find the attribute in the map
00257         AccessMapType::iterator i = m_map.find(name);
00258         if( i == m_map.end() )
00259                 return false;
00260 
00261         m_dnAttr = name;
00262         return true;
00263 }
00264 
00265 bool ContactLdif::SetObjectClass(const LdifAttribute &name,
00266                                  const std::string &objectClass)
00267 {
00268         AccessMapType::iterator i = m_map.find(name);
00269         if( i == m_map.end() )
00270                 return false;
00271 
00272         LdifAttribute key = i->first;
00273         AccessPair pair = i->second;
00274         m_map.erase(key);
00275         key.objectClass = objectClass;
00276         m_map[key] = pair;
00277         return true;
00278 }
00279 
00280 bool ContactLdif::SetObjectOrder(const LdifAttribute &name, int order)
00281 {
00282         AccessMapType::iterator i = m_map.find(name);
00283         if( i == m_map.end() )
00284                 return false;
00285 
00286         LdifAttribute key = i->first;
00287         AccessPair pair = i->second;
00288         m_map.erase(key);
00289         key.order = order;
00290         m_map[key] = pair;
00291         return true;
00292 }
00293 
00294 
00295 std::string ContactLdif::Email(const Barry::Contact &con) const
00296 {
00297         return con.GetEmail(m_emailIndex++);
00298 }
00299 
00300 std::string ContactLdif::Phone(const Barry::Contact &con) const
00301 {
00302         return con.Phone;
00303 }
00304 
00305 std::string ContactLdif::Fax(const Barry::Contact &con) const
00306 {
00307         return con.Fax;
00308 }
00309 
00310 std::string ContactLdif::WorkPhone(const Barry::Contact &con) const
00311 {
00312         return con.WorkPhone;
00313 }
00314 
00315 std::string ContactLdif::HomePhone(const Barry::Contact &con) const
00316 {
00317         return con.HomePhone;
00318 }
00319 
00320 std::string ContactLdif::MobilePhone(const Barry::Contact &con) const
00321 {
00322         return con.MobilePhone;
00323 }
00324 
00325 std::string ContactLdif::Pager(const Barry::Contact &con) const
00326 {
00327         return con.Pager;
00328 }
00329 
00330 std::string ContactLdif::PIN(const Barry::Contact &con) const
00331 {
00332         return con.PIN;
00333 }
00334 
00335 std::string ContactLdif::FirstName(const Barry::Contact &con) const
00336 {
00337         return con.FirstName;
00338 }
00339 
00340 std::string ContactLdif::LastName(const Barry::Contact &con) const
00341 {
00342         return con.LastName;
00343 }
00344 
00345 std::string ContactLdif::Company(const Barry::Contact &con) const
00346 {
00347         return con.Company;
00348 }
00349 
00350 std::string ContactLdif::DefaultCommunicationsMethod(const Barry::Contact &con) const
00351 {
00352         return con.DefaultCommunicationsMethod;
00353 }
00354 
00355 std::string ContactLdif::WorkAddress1(const Barry::Contact &con) const
00356 {
00357         return con.WorkAddress.Address1;
00358 }
00359 
00360 std::string ContactLdif::WorkAddress2(const Barry::Contact &con) const
00361 {
00362         return con.WorkAddress.Address2;
00363 }
00364 
00365 std::string ContactLdif::WorkAddress3(const Barry::Contact &con) const
00366 {
00367         return con.WorkAddress.Address3;
00368 }
00369 
00370 std::string ContactLdif::WorkCity(const Barry::Contact &con) const
00371 {
00372         return con.WorkAddress.City;
00373 }
00374 
00375 std::string ContactLdif::WorkProvince(const Barry::Contact &con) const
00376 {
00377         return con.WorkAddress.Province;
00378 }
00379 
00380 std::string ContactLdif::WorkPostalCode(const Barry::Contact &con) const
00381 {
00382         return con.WorkAddress.PostalCode;
00383 }
00384 
00385 std::string ContactLdif::WorkCountry(const Barry::Contact &con) const
00386 {
00387         return con.WorkAddress.Country;
00388 }
00389 
00390 std::string ContactLdif::JobTitle(const Barry::Contact &con) const
00391 {
00392         return con.JobTitle;
00393 }
00394 
00395 std::string ContactLdif::PublicKey(const Barry::Contact &con) const
00396 {
00397         return con.PublicKey;
00398 }
00399 
00400 std::string ContactLdif::Notes(const Barry::Contact &con) const
00401 {
00402         return con.Notes;
00403 }
00404 
00405 std::string ContactLdif::Image(const Barry::Contact &con) const
00406 {
00407         return con.Image;
00408 }
00409 
00410 std::string ContactLdif::WorkPostalAddress(const Barry::Contact &con) const
00411 {
00412         return con.WorkAddress.GetLabel();
00413 }
00414 
00415 std::string ContactLdif::HomePostalAddress(const Barry::Contact &con) const
00416 {
00417         return con.HomeAddress.GetLabel();
00418 }
00419 
00420 std::string ContactLdif::FullName(const Barry::Contact &con) const
00421 {
00422         return con.GetFullName();
00423 }
00424 
00425 std::string ContactLdif::FQDN(const Barry::Contact &con) const
00426 {
00427         std::string FQDN = m_dnAttr.name;
00428         FQDN += "=";
00429 
00430         AccessMapType::const_iterator i = m_map.find(m_dnAttr);
00431         if( i != m_map.end() ) {
00432                 FQDN += (this->*(i->second.read))(con);
00433         }
00434         else {
00435                 FQDN += "unknown";
00436         }
00437 
00438         FQDN += ",";
00439         FQDN += m_baseDN;
00440         return FQDN;
00441 }
00442 
00443 bool ContactLdif::IsArrayFunc(GetFunctionType getf) const
00444 {
00445         // Currently, only the Email getter has array data
00446         if( getf == &ContactLdif::Email )
00447                 return true;
00448         return false;
00449 }
00450 
00451 void ContactLdif::ClearArrayState() const
00452 {
00453         m_emailIndex = 0;
00454 }
00455 
00456 void ContactLdif::SetEmail(Barry::Contact &con, const std::string &val) const
00457 {
00458         con.EmailAddresses.push_back(val);
00459 }
00460 
00461 void ContactLdif::SetPhone(Barry::Contact &con, const std::string &val) const
00462 {
00463         con.Phone = val;
00464 }
00465 
00466 void ContactLdif::SetFax(Barry::Contact &con, const std::string &val) const
00467 {
00468         con.Fax = val;
00469 }
00470 
00471 void ContactLdif::SetWorkPhone(Barry::Contact &con, const std::string &val) const
00472 {
00473         con.WorkPhone = val;
00474 }
00475 
00476 void ContactLdif::SetHomePhone(Barry::Contact &con, const std::string &val) const
00477 {
00478         con.HomePhone = val;
00479 }
00480 
00481 void ContactLdif::SetMobilePhone(Barry::Contact &con, const std::string &val) const
00482 {
00483         con.MobilePhone = val;
00484 }
00485 
00486 void ContactLdif::SetPager(Barry::Contact &con, const std::string &val) const
00487 {
00488         con.Pager = val;
00489 }
00490 
00491 void ContactLdif::SetPIN(Barry::Contact &con, const std::string &val) const
00492 {
00493         con.PIN = val;
00494 }
00495 
00496 void ContactLdif::SetFirstName(Barry::Contact &con, const std::string &val) const
00497 {
00498         con.FirstName = val;
00499 }
00500 
00501 void ContactLdif::SetLastName(Barry::Contact &con, const std::string &val) const
00502 {
00503         con.LastName = val;
00504 }
00505 
00506 void ContactLdif::SetCompany(Barry::Contact &con, const std::string &val) const
00507 {
00508         con.Company = val;
00509 }
00510 
00511 void ContactLdif::SetDefaultCommunicationsMethod(Barry::Contact &con, const std::string &val) const
00512 {
00513         con.DefaultCommunicationsMethod = val;
00514 }
00515 
00516 void ContactLdif::SetWorkAddress1(Barry::Contact &con, const std::string &val) const
00517 {
00518         con.WorkAddress.Address1 = val;
00519 }
00520 
00521 void ContactLdif::SetWorkAddress2(Barry::Contact &con, const std::string &val) const
00522 {
00523         con.WorkAddress.Address2 = val;
00524 }
00525 
00526 void ContactLdif::SetWorkAddress3(Barry::Contact &con, const std::string &val) const
00527 {
00528         con.WorkAddress.Address3 = val;
00529 }
00530 
00531 void ContactLdif::SetWorkCity(Barry::Contact &con, const std::string &val) const
00532 {
00533         con.WorkAddress.City = val;
00534 }
00535 
00536 void ContactLdif::SetWorkProvince(Barry::Contact &con, const std::string &val) const
00537 {
00538         con.WorkAddress.Province = val;
00539 }
00540 
00541 void ContactLdif::SetWorkPostalCode(Barry::Contact &con, const std::string &val) const
00542 {
00543         con.WorkAddress.PostalCode = val;
00544 }
00545 
00546 void ContactLdif::SetWorkCountry(Barry::Contact &con, const std::string &val) const
00547 {
00548         con.WorkAddress.Country = val;
00549 }
00550 
00551 void ContactLdif::SetJobTitle(Barry::Contact &con, const std::string &val) const
00552 {
00553         con.JobTitle = val;
00554 }
00555 
00556 void ContactLdif::SetPublicKey(Barry::Contact &con, const std::string &val) const
00557 {
00558         con.PublicKey = val;
00559 }
00560 
00561 void ContactLdif::SetNotes(Barry::Contact &con, const std::string &val) const
00562 {
00563         con.Notes = val;
00564 }
00565 
00566 void ContactLdif::SetImage(Barry::Contact &con, const std::string &val) const
00567 {
00568         con.Image = val;
00569 }
00570 
00571 void ContactLdif::SetWorkPostalAddress(Barry::Contact &con, const std::string &val) const
00572 {
00573         // FIXME;
00574 //      throw std::runtime_error("SetWorkPostalAddress() not implemented");
00575 //      std::cout << "SetWorkPostalAddress() not implemented: " << val << std::endl;
00576 }
00577 
00578 void ContactLdif::SetHomePostalAddress(Barry::Contact &con, const std::string &val) const
00579 {
00580         // FIXME;
00581 //      throw std::runtime_error("SetHomePostalAddress() not implemented");
00582 //      std::cout << "SetHomePostalAddress() not implemented: " << val << std::endl;
00583 }
00584 
00585 void ContactLdif::SetFullName(Barry::Contact &con, const std::string &val) const
00586 {
00587         std::string first, last;
00588         Contact::SplitName(val, first, last);
00589         con.FirstName = first;
00590         con.LastName = last;
00591 }
00592 
00593 void ContactLdif::SetFQDN(Barry::Contact &con, const std::string &val) const
00594 {
00595         throw std::runtime_error("not implemented");
00596 }
00597 
00598 
00599 void ContactLdif::ClearHeuristics()
00600 {
00601         m_cn.clear();
00602         m_displayName.clear();
00603         m_sn.clear();
00604         m_givenName.clear();
00605 }
00606 
00607 bool ContactLdif::RunHeuristics(Barry::Contact &con)
00608 {
00609         // start fresh
00610         con.LastName.clear();
00611         con.FirstName.clear();
00612 
00613         // find the best match for name... prefer sn/givenName if available
00614         if( m_sn.size() ) {
00615                 con.LastName = m_sn;
00616         }
00617         if( m_givenName.size() ) {
00618                 con.FirstName = m_givenName;
00619         }
00620 
00621         if( !con.LastName.size() || !con.FirstName.size() ) {
00622                 std::string first, last;
00623 
00624                 // still don't have a complete name, check cn first
00625                 if( m_cn.size() ) {
00626                         Contact::SplitName(m_cn, first, last);
00627                         if( !con.LastName.size() && last.size() )
00628                                 con.LastName = last;
00629                         if( !con.FirstName.size() && first.size() )
00630                                 con.FirstName = first;
00631                 }
00632 
00633                 // displayName is last chance
00634                 if( m_displayName.size() ) {
00635                         Contact::SplitName(m_displayName, first, last);
00636                         if( !con.LastName.size() && last.size() )
00637                                 con.LastName = last;
00638                         if( !con.FirstName.size() && first.size() )
00639                                 con.FirstName = first;
00640                 }
00641         }
00642 
00643         return con.LastName.size() && con.FirstName.size();
00644 }
00645 
00646 
00647 //
00648 // DumpLdif
00649 //
00650 /// Output contact data to os in LDAP LDIF format.
00651 ///
00652 void ContactLdif::DumpLdif(std::ostream &os,
00653                        const Barry::Contact &con) const
00654 {
00655         // start fresh
00656         ClearArrayState();
00657 
00658         // setup stream state
00659         std::ios::fmtflags oldflags = os.setf(std::ios::left);
00660         char fill = os.fill(' ');
00661 
00662         if( FirstName(con).size() == 0 && LastName(con).size() == 0 )
00663                 return;                 // nothing to do
00664 
00665         os << "# Contact 0x" << std::hex << con.GetID() << ", "
00666                 << FullName(con) << "\n";
00667 
00668         // cycle through the map
00669         for(    AccessMapType::const_iterator b = m_map.begin();
00670                 b != m_map.end();
00671                 ++b )
00672         {
00673                 // print only fields with data
00674                 std::string field;
00675 
00676                 do {
00677                         field = (this->*(b->second.read))(con);
00678                         if( field.size() ) {
00679                                 os << b->first.name << MakeLdifData(field) << "\n";
00680                                 if( b->first.objectClass.size() )
00681                                         os << "objectClass: " << b->first.objectClass << "\n";
00682                         }
00683                 } while( IsArrayFunc(b->second.read) && field.size() );
00684         }
00685 
00686         os << "objectClass: inetOrgPerson\n";
00687 
00688         // last line must be empty
00689         os << "\n";
00690 
00691         // cleanup the stream
00692         os.flags(oldflags);
00693         os.fill(fill);
00694 }
00695 
00696 bool ContactLdif::ReadLdif(std::istream &is, Barry::Contact &con)
00697 {
00698         std::string line;
00699 
00700         // start fresh
00701         con.Clear();
00702         ClearHeuristics();
00703 
00704         // search for beginning dn: line
00705         bool found = false;
00706         while( std::getline(is, line) ) {
00707                 if( strncmp(line.c_str(), "dn: ", 4) == 0 ) {
00708                         found = true;
00709                         break;
00710                 }
00711         }
00712         if( !found )
00713                 return false;
00714 
00715         // storage for various name styles
00716         std::string coded, decode, attr, data;
00717         bool b64field = false;
00718 
00719         // read ldif lines until empty line is found
00720         while( getline(is, line) && line.size() ) {
00721 
00722                 if( b64field ) {
00723                         // processing a base64 encoded field
00724                         if( line[0] == ' ' ) {
00725                                 coded += "\n";
00726                                 coded += line;
00727                                 continue;
00728                         }
00729                         else {
00730                                 // end of base64 block... ignore errors,
00731                                 // and attempt to save everything decodable...
00732                                 // the LDAP server sometimes returns incomplete
00733                                 // base64 encoding, but otherwise the data is fine
00734                                 base64_decode(coded, decode);
00735                                 DoWrite(con, attr, decode);
00736                                 coded.clear();
00737                                 b64field = false;
00738                         }
00739                         // fall through to process new line
00740                 }
00741 
00742 
00743                 // split into attribute / data
00744                 std::string::size_type delim = line.find(':'), dstart;
00745                 if( delim == std::string::npos )
00746                         continue;
00747 
00748                 attr.assign(line, 0, delim);
00749                 dstart = delim + 1;
00750                 while( line[dstart] == ' ' || line[dstart] == ':' )
00751                         dstart++;
00752                 data = line.substr(dstart);
00753 
00754                 // is this data base64 encoded?
00755                 if( line[delim + 1] == ':' ) {
00756                         coded = data;
00757                         b64field = true;
00758                         continue;
00759                 }
00760 
00761                 DoWrite(con, attr, data);
00762         }
00763 
00764         if( b64field ) {
00765                 // clean up base64 decoding... ignore errors, see above comment
00766                 base64_decode(coded, decode);
00767                 DoWrite(con, attr, decode);
00768                 coded.clear();
00769                 b64field = false;
00770         }
00771 
00772         return RunHeuristics(con);
00773 }
00774 
00775 void ContactLdif::DumpMap(std::ostream &os) const
00776 {
00777         std::ios::fmtflags oldflags = os.setf(std::ios::left);
00778         char fill = os.fill(' ');
00779 
00780         os << "ContactLdif Mapping:\n";
00781 
00782         // cycle through the map
00783         for(    AccessMapType::const_iterator b = m_map.begin();
00784                 b != m_map.end();
00785                 ++b )
00786         {
00787                 os << "   " << std::left << std::setw(20) << b->first.name
00788                    << "->  " << GetFieldReadName(b->second.read)
00789                    << " / " << GetFieldWriteName(b->second.write) << "\n";
00790 
00791                 // find read/write names
00792 
00793                 if( b->first.objectClass.size() ) {
00794                         os << "   " << std::setw(20) << " "
00795                            << "objectClass: " << b->first.objectClass << "\n";
00796                 }
00797         }
00798 
00799         os << "   >>> DN attribute: " << m_dnAttr.name << "\n";
00800 
00801         // cleanup the stream
00802         os.flags(oldflags);
00803         os.fill(fill);
00804 }
00805 
00806 std::string ContactLdif::MakeLdifData(const std::string &str)
00807 {
00808         std::string data = ":";
00809 
00810         if( NeedsEncoding(str) ) {
00811                 std::string b64;
00812                 base64_encode(str, b64);
00813 
00814                 data += ": ";
00815                 data += b64;
00816         }
00817         else {
00818                 data += " ";
00819                 data += str;
00820         }
00821 
00822         return data;
00823 }
00824 
00825 //
00826 // RFC 2849
00827 //
00828 // Must not contain:
00829 //      0x00 (NUL), 0x0a (LF), 0x0d (CR), or anything greater than 0x7f
00830 //
00831 // First char must meet above criteria, plus must not be:
00832 //      0x20 (SPACE), 0x3a (colon), 0x3c ('<')
00833 //
00834 bool ContactLdif::NeedsEncoding(const std::string &str)
00835 {
00836         for( std::string::size_type i = 0; i < str.size(); i++ ) {
00837                 unsigned char c = str[i];
00838 
00839                 switch( c )
00840                 {
00841                 case 0x00:
00842                 case 0x0a:
00843                 case 0x0d:
00844                         return true;
00845 
00846                 case 0x20:
00847                 case 0x3a:
00848                 case 0x3c:
00849                         if( i == 0 )
00850                                 return true;
00851                 }
00852 
00853                 if( c > 0x7f )
00854                         return true;
00855         }
00856         return false;
00857 }
00858 
00859 } // namespace Barry
00860 

Generated on Tue Mar 1 17:50:15 2011 for Barry by  doxygen 1.5.6