#include #include #include "gsdlsitecfg.h" #include "recptprototools.h" #import #import #import #import #import "GSResultItem.h" #import "GreenstoneAPI.h" GreenstoneAPI::GreenstoneAPI(UIApplication* toplevelApp) : _toplevelApp(toplevelApp), _lang("en"), _cservers(nil), _nproto(nil), _gsdlhome() { _cservers = new collectset(_gsdlhome); // sets gsdlhome // set up the null protocol _nproto = new nullproto(); _nproto->set_collectset(_cservers); comerror_t comerr; _nproto->init(comerr,cerr); if (comerr!=noError) { text_t error_message = get_comerror_string (comerr); alert("Error",error_message); } } GreenstoneAPI::~GreenstoneAPI() { delete _cservers; delete _nproto; } void GreenstoneAPI::alert(NSString* nslevel, NSString* nsmessage) { // Allert sheet displayed at centre of screen. NSArray *buttons = [NSArray arrayWithObjects:@"OK", nil]; UIAlertSheet *alertSheet = [UIAlertSheet alloc]; [alertSheet initWithTitle:nslevel buttons:buttons defaultButtonIndex:1 delegate:_toplevelApp context:nil]; [alertSheet setBodyText:nsmessage]; [alertSheet popupAlertAnimated:YES]; } void GreenstoneAPI::alert(char* level, char* message) { // Alert sheet displayed at centre of screen. NSString* nslevel = [[NSString alloc] initWithCString: level]; NSString* nsmessage = [[NSString alloc] initWithCString: message]; alert(nslevel,nsmessage); [nslevel release]; [nsmessage release]; } void GreenstoneAPI::alert(text_t level, text_t message) { char* level_cstr = level.getcstr(); char* message_cstr = message.getcstr(); alert(level_cstr,message_cstr); delete [] level_cstr; delete [] message_cstr; } bool GreenstoneAPI::sanityCheck() { text_t gsdl_home, unused_collecthome; text_t unused_httpdomain,unused_httpprefix; if (!site_cfg_read(gsdl_home,unused_collecthome, unused_httpdomain,unused_httpprefix)) { // couldn't find gsdlsite.cfg file char cwd[128]; getcwd(cwd,128); text_t sitecfg_filename = cwd; sitecfg_filename += "gsdlsite.cfg"; alert("Error","Unable to find " + sitecfg_filename ); return false; } text_t collect_dir = filename_cat(gsdl_home,"collect"); char* collect_dir_cstr = collect_dir.getcstr(); DIR* directorypointer = opendir(collect_dir_cstr); delete [] collect_dir_cstr; if(directorypointer == NULL) //If the directory could not be opened { text_t mess = "No collections directory. Please make one at: " + collect_dir; alert("Error",mess); return false; } return true; } NSMutableArray* GreenstoneAPI::collectionList() { text_tarray collection_list; comerror_t comerr; _nproto->get_collection_list (collection_list, comerr, cerr); if (comerr != noError) { alert("Error",get_comerror_string(comerr)); return nil; } int num_cols = collection_list.size(); NSMutableArray* nscollist = [[NSMutableArray alloc] initWithCapacity:num_cols]; text_tarray::iterator collection_iterator = collection_list.begin(); while (collection_iterator != collection_list.end()) { text_t& colname = *collection_iterator; char* colname_cstr = colname.getcstr(); NSString* nscolname = [[NSString alloc ] initWithCString: colname_cstr]; delete [] colname_cstr; [nscollist addObject:nscolname]; collection_iterator++; } return nscollist; } ColInfoResponse_t& GreenstoneAPI::collectInfo (const text_t &collection) { ColInfoResponse_t& collectinfo = *new ColInfoResponse_t(); comerror_t comerr; _nproto->get_collectinfo(collection, collectinfo,comerr, cerr); if (comerr != noError) { alert("Error",get_comerror_string(comerr)); } return collectinfo; } ColInfoResponse_t& GreenstoneAPI::collectInfo (NSString* nscollection) { char const* nscollection_cstr = [nscollection UTF8String]; ColInfoResponse_t& colinfo = collectInfo(nscollection_cstr); // according to documentation, nscollectcion_cstr autorealeased // => don't need to free them return colinfo; } /* **** text_t GreenstoneAPI::lookupLanguagePref() { NSString* nslang = [(GreenstoneApplication*)_toplevelApp languagePref]; char* lang_cstr = [nslang UTF8String]; text_t lang = lang_cstr; [nslang release]; return lang; } */ NSString* GreenstoneAPI::collectionmetaValue(ColInfoResponse_t& colinfo, text_t key) { text_t val = colinfo.get_collectionmeta(key,_lang); char* val_cstr = val.getcstr(); NSString* nsval = [[NSString alloc] initWithCString:val_cstr]; delete [] val_cstr; return nsval; } NSString* GreenstoneAPI::collectionName(ColInfoResponse_t& colinfo) { return collectionmetaValue(colinfo,"collectionname"); } NSString* TextTToNSString(text_t& text) { // Make this available to other parts of program!!! if (text.empty()) { return nil; } char* text_cstr = text.getcstr(); NSString* nstext = [[NSString alloc ] initWithCString: text_cstr]; delete [] text_cstr; return nstext; } bool GreenstoneAPI::recurse_contents(const text_t& collection, ResultDocInfo_t& section, text_tset& metadata, text_t& output_text) { // Output this section // 1. Get the title text_t title = section.metadata["Title"].values[0]; output_text.append("

"+title+"

"); // cerr << "**** Title = " << title << endl; // 2. Get the text DocumentRequest_t docrequest; DocumentResponse_t docresponse; comerror_t comerr; docrequest.OID = section.OID; _nproto->get_document(collection, docrequest, docresponse, comerr, cerr); if (comerr != noError) { alert("Error",get_comerror_string(comerr)); return false; } output_text.append(docresponse.doc); // cerr << "*** appending text " << docresponse.doc << endl; int haschildren = section.metadata["haschildren"].values[0].getint(); // recurse through children if (haschildren == 1) { bool getParents = false; FilterResponse_t tmp; get_children (section.OID, collection, _lang, metadata, getParents, _nproto, tmp, cerr); ResultDocInfo_tarray::iterator thisdoc = tmp.docInfo.begin(); ResultDocInfo_tarray::iterator lastdoc = tmp.docInfo.end(); while (thisdoc != lastdoc) { bool recurse_ok = recurse_contents(collection,*thisdoc, metadata, output_text); if (!recurse_ok) { return false; } ++thisdoc; } } return true; } NSString* GreenstoneAPI::getResolvedDocument(NSString* nscollection, NSString* nsgid) { char const* nscollection_cstr = [nscollection UTF8String]; char const* nsgid_cstr = [nsgid UTF8String]; text_t collection(nscollection_cstr); text_t gid(nsgid_cstr); //metadata elements needed by recurse_contents text_tset metadata; metadata.insert ("Title"); metadata.insert ("haschildren"); bool getParents = false; FilterResponse_t inforesponse; comerror_t comerr; NSString* nsresolvedtext = nil; if (get_info(gid, collection, _lang, metadata, getParents, _nproto, inforesponse, cerr)) { text_t output_text; text_t make_utf8 = " \n"; output_text.append("\n"); output_text.append(" \n"+make_utf8+" \n"); if (recurse_contents(collection,inforesponse.docInfo[0], metadata, output_text)) { // cerr << "**** text = " << output_text << endl; // retrieve [archivedir] for this document id NSString* nsarchivedir = getMetadataFirst(nscollection,nsgid,@"archivedir"); const char* nsarchivedir_cstr = [nsarchivedir UTF8String]; text_t archivedir = nsarchivedir_cstr; [nsarchivedir release]; text_t resolved_text = resolveUrls(output_text,collection,archivedir); char* resolved_text_cstr = resolved_text.getcstr(); nsresolvedtext = [[NSString alloc] initWithCString:resolved_text_cstr]; delete [] resolved_text_cstr; } else { alert("Error","Failed to get info for " + gid); } output_text.append("\n"); } else { alert("Error","Failed to get info for " + gid); } return nsresolvedtext; } NSMutableArray* GreenstoneAPI::getMetadata(NSString* nscollection, NSString* nsgid, NSString* nsmetaname) { char const* nscollection_cstr = [nscollection UTF8String]; char const* nsgid_cstr = [nsgid UTF8String]; char const* nsmetaname_cstr = [nsmetaname UTF8String]; NSMutableArray* nsmdlist = nil; text_t collection(nscollection_cstr); text_t gid(nsgid_cstr); text_t metaname(nsmetaname_cstr); text_tset metadata; metadata.insert (metaname); bool getParents = false; FilterResponse_t response; if (get_info (gid, collection, _lang, metadata, getParents, _nproto, response, cerr)) { int num_browse_by = response.docInfo.size(); if (num_browse_by>0) { MetadataInfo_tmap& metadata = response.docInfo[0].metadata; MetadataInfo_t& metaname_info = metadata[nsmetaname_cstr]; int num_browse_by = metaname_info.values.size(); if (num_browse_by>0) { // protocol will return 1 even if there is no metadata // values will be the empty string nsmdlist = [[NSMutableArray alloc] initWithCapacity:num_browse_by]; text_tarray& meta_val = metaname_info.values; text_tarray::iterator md_iterator = meta_val.begin(); while (md_iterator != meta_val.end()) { text_t& mdval = *md_iterator; NSString* nsmdval = TextTToNSString(mdval); if (nsmdval != nil) { [nsmdlist addObject:nsmdval]; } md_iterator++; } if ([nsmdlist count] == 0) { // no valid metadata => free list and set to nil [nsmdlist release]; nsmdlist = nil; } } else { alert("Error","OID" + gid + "does not have metadata for" + metaname); } } else { alert("Error","OID" + gid + "does not have metadata for" + metaname); } } else { alert("Error","Collection has no browsing capabilities" + gid); } // according to documentation, nscollectcion_cstr, nsgid_cstr and nsmetaname_cstr autorealeased // => don't need to free them return nsmdlist; } NSString* GreenstoneAPI::getMetadataFirst(NSString* nscollection, NSString* nsgid, NSString* nsmetaname) { NSMutableArray* all_metavalues = getMetadata(nscollection,nsgid,nsmetaname); NSString* first_metavalue_copy = nil; if (all_metavalues != nil) { NSString* first_metavalue = [all_metavalues objectAtIndex:0]; first_metavalue_copy = [[NSString alloc] initWithString:first_metavalue]; [all_metavalues release]; } return first_metavalue_copy; } NSString* GreenstoneAPI::getMetadataFirst(const text_t& collection, text_t& gid, text_t& metaname) { char* collection_cstr = collection.getcstr(); char* gid_cstr = gid.getcstr(); char* metaname_cstr = metaname.getcstr(); NSString* nscollection = [[NSString alloc] initWithCString:collection_cstr]; NSString* nsgid = [[NSString alloc] initWithCString:gid_cstr]; NSString* nsmetaname = [[NSString alloc] initWithCString:metaname_cstr]; NSString* result = getMetadataFirst(nscollection,nsgid,nsmetaname); delete [] collection_cstr; delete [] gid_cstr; delete [] metaname_cstr; return result; } NSMutableArray* GreenstoneAPI::browseClassifierList(NSString* nscollection, NSString* nsgid) { // **** upgrade this to use getMetadata, and then split on ';' char const* nscollection_cstr = [nscollection UTF8String]; char const* nsgid_cstr = [nsgid UTF8String]; text_t gid = nsgid_cstr; NSMutableArray* nscllist = nil; text_tset metadata; metadata.insert ("contains"); FilterResponse_t response; comerror_t comerr; if (get_info (nsgid_cstr, nscollection_cstr, _lang, metadata, false, _nproto, response, cerr)) { int num_browse_by = response.docInfo.size(); if (num_browse_by >0) { MetadataInfo_tmap& metadata = response.docInfo[0].metadata; MetadataInfo_t& contains = metadata["contains"]; int num_browse_by = contains.values.size(); if (num_browse_by>0) { // nscllist = [[NSMutableArray alloc] initWithCapacity:num_browse_by]; **** nscllist = [[NSMutableArray alloc] initWithCapacity:50]; text_tarray& contains_val = contains.values; text_tarray::iterator cl_iterator = contains_val.begin(); while (cl_iterator != contains_val.end()) { text_t& clname = *cl_iterator; // split up on ';' text_tarray split_clname; splitchar (clname.begin(), clname.end(), ';', split_clname); text_tarray::iterator split_cl_iterator = split_clname.begin(); while (split_cl_iterator != split_clname.end()) { text_t& cl = *split_cl_iterator; NSString* nscl = nil; if (cl[0] == '\"') { text_t cl_trim = substr(cl.begin()+1,cl.end()); nscl = TextTToNSString(cl_trim); } else { nscl = TextTToNSString(cl); } if (nscl != nil) { [nscllist addObject:nscl]; } else { cerr << "Warning: no semicolon split classifier 'contains' metadata value found for " + gid << endl; } split_cl_iterator++; } cl_iterator++; } if ([nscllist count]==0) { // No valid metadata found [nscllist release]; nscllist = nil; } } else { alert("Error","Collection has to browsing capabilities"); } } else { alert("Error","Collection has to browsing capabilities"); } } else { alert("Error",get_comerror_string(comerr)); } // according to documentation, nscollectcion_cstr and nsgid_cstr autorealeased // => don't need to free them return nscllist; } NSMutableArray* GreenstoneAPI::browseToplevelList(NSString* nscollection) { return browseClassifierList(nscollection,@"browse"); } void GreenstoneAPI::set_queryfilter_options (const text_t& collection, FilterRequest_t &request, const text_t &querystring) { ColInfoResponse_t& collectinfo = collectInfo(collection); // request.filterResultOptions and request.fields (if required) should // be set from the calling code request.filterName = "QueryFilter"; OptionValue_t option; option.name = "Term"; option.value = querystring; request.filterOptions.push_back (option); option.name = "QueryType"; option.value = "ranked"; request.filterOptions.push_back (option); option.name = "MatchMode"; option.value = "some"; request.filterOptions.push_back (option); option.name = "Casefold"; option.value = "true"; request.filterOptions.push_back (option); option.name = "Stem"; option.value = "true"; request.filterOptions.push_back (option); option.name = "AccentFold"; option.value = "true"; request.filterOptions.push_back (option); text_t buildtype = collectinfo.buildType; if (buildtype == "lucene") { // Should prevent Lucene collection from doing any searching!! // **** alert("Warning","Searching lucene indexed collection on iPod not currently supported"); } else if (buildtype == "mgpp") { option.name = "Level"; option.value = "Doc"; request.filterOptions.push_back (option); option.name = "Index"; option.value = "idx"; // **** request.filterOptions.push_back (option); } else { cerr << "**** storing index as dte" << endl; option.name = "Index"; option.value = "dte"; // **** request.filterOptions.push_back (option); } option.name = "Maxdocs"; option.value = "50"; request.filterOptions.push_back (option); option.name = "StartResults"; option.value = "1"; request.filterOptions.push_back (option); option.name = "EndResults"; option.value = "50"; request.filterOptions.push_back (option); } text_t GreenstoneAPI::resolveUrls(const text_t& unresolved, const text_t& collection, const text_t& archivedir) { text_t resolved = unresolved; text_t httpprefix = _gsdlhome; text_t httpdocimg = httpprefix +"/collect/" + collection + "/index/assoc/" + archivedir; resolved.replace("[archivedir]",archivedir); resolved.replace("[assocfilepath]",archivedir); resolved.replace("[collection]",collection); resolved.replace("_httpprefix_",httpprefix); resolved.replace("_httpdocimg_",httpdocimg); return resolved; } text_t GreenstoneAPI::srclinkToUrl(const text_t& srclink, const text_t& collection, const text_t& archivedir) { text_t srcurl; if (!srclink.empty()) { // extract URL text_tarray split_srclink; splitchar (srclink.begin(), srclink.end(), '\"', split_srclink); if (split_srclink.size()>=2) { srcurl = resolveUrls(split_srclink[1],collection,archivedir); } } return srcurl; } NSString* GreenstoneAPI::getSrcUrlMetadata(NSString* nscollection, NSString* nsgid) { NSString* nssrclink = getMetadataFirst(nscollection,nsgid,@"srclink"); if (nssrclink == nil) { return nil; } NSString* nsarchivedir = getMetadataFirst(nscollection,nsgid,@"archivedir"); //NSString* nsassocfilepath = getMetadataFirst(nscollection,nsgid,@"assocfilepath"); // ****** used? char const* nscollection_cstr = [nscollection UTF8String]; char const* nssrclink_cstr = [nssrclink UTF8String]; char const* nsarchivedir_cstr = [nsarchivedir UTF8String]; text_t collection = nscollection_cstr; text_t srclink = nssrclink_cstr; text_t archivedir = nsarchivedir_cstr; text_t srcurl = srclinkToUrl(srclink,collection,archivedir); NSString* nsimage = getMetadataFirst(nscollection,nsgid,@"Image"); char const* image_cstr = [nsimage UTF8String]; srcurl.replace("[Image]",image_cstr); NSString* nssrcurl = TextTToNSString(srcurl); return nssrcurl; } NSMutableArray* GreenstoneAPI::filterResponseToTitlesList(const text_t& collection, FilterResponse_t& sections) { ResultDocInfo_tarray::iterator thissection = sections.docInfo.begin(); ResultDocInfo_tarray::iterator endsection = sections.docInfo.end(); int num_results = sections.docInfo.size(); NSMutableArray* nsresultlist = nil; if (num_results>0) { nsresultlist = [[NSMutableArray alloc] initWithCapacity:num_results]; while (thissection != endsection) { ResultDocInfo_t &docinfo = *thissection; text_t& oid = docinfo.OID; text_t title; text_t srcurl; MetadataInfo_tmap& metadata = docinfo.metadata; MetadataInfo_t& dctitle_info = metadata["dc.Title"]; MetadataInfo_t& title_info = metadata["Title"]; if ((dctitle_info.values.size()>0) && (!dctitle_info.values[0].empty())) { title = dctitle_info.values[0]; } else if ((title_info.values.size()>0) && (!title_info.values[0].empty())) { title = title_info.values[0]; } else { cerr << "Warning: could not find Title metadata for item" << endl; } MetadataInfo_t& archivedir_info = metadata["archivedir"]; text_t archivedir = archivedir_info.values[0]; MetadataInfo_t& srclink_info = metadata["srclink"]; if (srclink_info.values.size()>0) { text_t& srclink = srclink_info.values[0]; srcurl = srclinkToUrl(srclink,collection,archivedir); // ** think about embedding in routine? text_t imagemdname = "Image"; NSString* nsimage = getMetadataFirst(collection,oid,imagemdname); //char const* image_cstr = [nsimage UTF8String]; //text_t image = image_cstr; //srcurl.replace("[Image]",image); } NSString* nstitle = TextTToNSString(title); NSString* nsoid = TextTToNSString(oid); NSString* nssrcurl = TextTToNSString(srcurl); GSResultItem* result_item = [[GSResultItem alloc] initWithOID:nsoid withTitle:nstitle withSrcUrl:nssrcurl]; [nsresultlist addObject:result_item]; ++thissection; } } return nsresultlist; } NSMutableArray* GreenstoneAPI::search_single_collection (const text_t& collection, const text_t& query) { comerror_t comerr; FilterRequest_t request; FilterResponse_t response; NSMutableArray* nsresultlist = nil; // request.fields = metadata set request.fields.insert ("dc.Title"); request.fields.insert ("Title"); request.fields.insert ("srclink"); request.fields.insert ("archivedir"); // do the query request.filterResultOptions = FROID | FRmetadata | FRtermFreq; text_t formattedstring = query; // note! formattedstring is in unicode! mg and mgpp must convert! set_queryfilter_options (collection, request, formattedstring); _nproto->filter (collection, request, response, comerr, cerr); if (comerr != noError) { alert("Error",get_comerror_string(comerr)); return nil; } else { nsresultlist = filterResponseToTitlesList(collection,response); } return nsresultlist; } NSMutableArray* GreenstoneAPI::query(NSString* nscollection, NSString* nsquery) { char const* nscollection_cstr = [nscollection UTF8String]; char const* nsquery_cstr = [nsquery UTF8String]; text_t collection = nscollection_cstr; text_t query = nsquery_cstr; NSMutableArray* nsresultlist = search_single_collection(collection,query); return nsresultlist; } NSString* GreenstoneAPI::getDocument(NSString* nscollection, NSString* nsgid) { char const* nscollection_cstr = [nscollection UTF8String]; char const* nsgid_cstr = [nsgid UTF8String]; text_t gid = nsgid_cstr; text_t collection = nscollection_cstr; DocumentRequest_t docrequest; DocumentResponse_t docresponse; comerror_t comerr; // get the text docrequest.OID = gid; _nproto->get_document(collection, docrequest, docresponse, comerr, cerr); if (comerr != noError) { alert("Error",get_comerror_string(comerr)); return nil; } text_t& text = docresponse.doc; char* text_cstr = text.getcstr(); NSString* nstext = [[NSString alloc] initWithCString:text_cstr]; delete [] text_cstr; return nstext; }