platform/shared/common/RhodesApp.cpp in rhodes-1.5.5 vs platform/shared/common/RhodesApp.cpp in rhodes-2.0.0.beta1

- old
+ new

@@ -8,10 +8,13 @@ #include "ruby/ext/rho/rhoruby.h" //#include <math.h> #include "sync/ClientRegister.h" #include "sync/SyncThread.h" #include "net/AsyncHttp.h" +#include "unzip/unzip.h" +#include "net/URI.h" +#include "rubyext/WebView.h" #ifdef OS_WINCE #include <winsock.h> #endif //#include "shttpd/src/shttpd.h" @@ -25,11 +28,11 @@ void rho_sync_create(); void rho_sync_destroy(); void rho_sync_doSyncAllSources(int show_status_popup); void rho_map_location(char* query); void rho_appmanager_load( void* httpContext, const char* szQuery); -void webview_navigate(char* url, int index); +void rho_db_init_attr_manager(); } namespace rho { namespace common{ @@ -56,14 +59,10 @@ CRhodesApp::CRhodesApp(const String& strRootPath) : CRhoThread(createClassFactory()) { m_strRhoRootPath = strRootPath; m_bExit = false; -#if !defined(RHO_HTTPD_COMMON_IMPL) - m_shttpdCtx = 0; -#endif - m_ptrFactory = createClassFactory(); m_NetRequest = m_ptrFactory->createNetRequest(); m_oGeoLocation.init(m_ptrFactory); #if defined( OS_WINCE ) || defined (OS_WINDOWS) @@ -87,10 +86,11 @@ void CRhodesApp::run() { LOG(INFO) + "Starting RhodesApp main routine..."; initHttpServer(); RhoRubyStart(); + rho_db_init_attr_manager(); LOG(INFO) + "Starting sync engine..."; rho_sync_create(); LOG(INFO) + "RhoRubyInitApp..."; RhoRubyInitApp(); @@ -101,38 +101,16 @@ getSplashScreen().hide(); LOG(INFO) + "navigate to first start url"; navigateToUrl(getFirstStartUrl()); -#if !defined(RHO_HTTPD_COMMON_IMPL) - while(!m_bExit) - { - shttpd_poll( m_shttpdCtx, 100000 ); - -//#if defined(OS_WINCE) - //GPS - //CGPSController::CheckTimeout(); -//#endif - } -#else m_httpServer->run(); -#endif LOG(INFO) + "RhodesApp thread shutdown"; RhoRubyStop(); rho_sync_destroy(); - -#if !defined(RHO_HTTPD_COMMON_IMPL) - shttpd_fini(m_shttpdCtx); -#endif - -//#if defined(OS_WINCE) -// CGPSController* pGPS = CGPSController::Instance(); -// pGPS->DeleteInstance(); -//#endif - } CRhodesApp::~CRhodesApp(void) { stopApp(); @@ -146,15 +124,11 @@ void CRhodesApp::stopApp() { if (!m_bExit) { m_bExit = true; -#if !defined(RHO_HTTPD_COMMON_IMPL) - shutdown_poll(m_shttpdCtx); -#else m_httpServer->stop(); -#endif //RHO_HTTPD_COMMON_IMPL stop(2000); } rho_asynchttp_destroy(); } @@ -187,10 +161,17 @@ rho_ruby_activateApp(); String strMsg; rho_http_sendresponse(arg, strMsg.c_str()); } +static void callback_loadserversources(void *arg, String const &strQuery) +{ + rho_ruby_loadserversources(strQuery.c_str()); + String strMsg; + rho_http_sendresponse(arg, strMsg.c_str()); +} + void CRhodesApp::callAppActiveCallback(boolean bActive) { m_httpServer->pause(!bActive); if (bActive) { @@ -214,11 +195,11 @@ if ( bCancel ) strBody = "status=cancel&message=User canceled operation."; else strBody = "status=error&message=" + strError; }else - strBody = "status=ok&image_uri=%2Fpublic%2Fdb-files%2F" + strImagePath; + strBody = "status=ok&image_uri=db%2Fdb-files%2F" + strImagePath; strBody += "&rho_callback=1"; NetRequest( getNet().pushData( strCallbackUrl, strBody, null ) ); } @@ -239,29 +220,29 @@ strBody += "&rho_callback=1"; NetRequest( getNet().pushData( strCallbackUrl, strBody, null ) ); } -static void callback_syncdb(void *arg -#if defined(RHO_HTTPD_COMMON_IMPL) - , String const &/*query*/ -#endif - ) +void CRhodesApp::callPopupCallback(String strCallbackUrl, const String &id, const String &title) { + if ( strCallbackUrl.length() == 0 ) + return; + + strCallbackUrl = canonicalizeRhoUrl(strCallbackUrl); + String strBody = "button_id=" + id + "&button_title=" + title; + strBody += "&rho_callback=1"; + NetRequest( getNet().pushData( strCallbackUrl, strBody, null ) ); +} + +static void callback_syncdb(void *arg, String const &/*query*/ ) +{ rho_sync_doSyncAllSources(1); rho_http_sendresponse(arg, ""); } -static void callback_redirect_to(void *arg -#if defined(RHO_HTTPD_COMMON_IMPL) - , String const &strQuery -#endif - ) +static void callback_redirect_to(void *arg, String const &strQuery ) { -#if !defined(RHO_HTTPD_COMMON_IMPL) - String strQuery = shttpd_get_env((shttpd_arg *)arg,"QUERY_STRING"); -#endif size_t nUrl = strQuery.find("url="); String strUrl; if ( nUrl != String::npos ) strUrl = strQuery.substr(nUrl+4); @@ -269,41 +250,23 @@ strUrl = "/app/"; rho_http_redirect(arg, strUrl.c_str()); } -static void callback_map(void *arg -#if defined(RHO_HTTPD_COMMON_IMPL) - , String const &query -#endif - ) +static void callback_map(void *arg, String const &query ) { -#if !defined(RHO_HTTPD_COMMON_IMPL) - String query = shttpd_get_env((shttpd_arg *)arg,"QUERY_STRING"); -#endif rho_map_location( const_cast<char*>(query.c_str()) ); rho_http_sendresponse(arg, ""); } -static void callback_shared(void *arg -#if defined(RHO_HTTPD_COMMON_IMPL) - , String const &/*query*/ -#endif - ) +static void callback_shared(void *arg, String const &/*query*/) { rho_http_senderror(arg, 404, "Not Found"); } -static void callback_AppManager_load(void *arg -#if defined(RHO_HTTPD_COMMON_IMPL) - , String const &query -#endif - ) +static void callback_AppManager_load(void *arg, String const &query ) { -#if !defined(RHO_HTTPD_COMMON_IMPL) - String query = shttpd_get_env((shttpd_arg *)arg,"QUERY_STRING"); -#endif rho_appmanager_load( arg, query.c_str() ); } static void callback_getrhomessage(void *arg, String const &strQuery) { @@ -345,36 +308,20 @@ void CRhodesApp::initHttpServer() { String strAppRootPath = getRhoRootPath() + "apps"; -#if !defined(RHO_HTTPD_COMMON_IMPL) - LOG(INFO) + "Init http server"; - m_shttpdCtx = shttpd_init(0,NULL); - - shttpd_set_option(m_shttpdCtx, "root", strAppRootPath.c_str()); - shttpd_set_option(m_shttpdCtx, "ports", getFreeListeningPort()); - - //shttpd_register_uri(m_shttpdCtx, "/system/geolocation", &CGPSController::show_geolocation, NULL); - shttpd_register_uri(m_shttpdCtx, "/system/geolocation", callback_geolocation, this); - shttpd_register_uri(m_shttpdCtx, "/system/syncdb", callback_syncdb, this); - shttpd_register_uri(m_shttpdCtx, "/system/redirect_to", callback_redirect_to, this); - shttpd_register_uri(m_shttpdCtx, "/system/map", callback_map, this); - shttpd_register_uri(m_shttpdCtx, "/system/shared", callback_shared, this); - shttpd_register_uri(m_shttpdCtx, "/AppManager/loader/load", callback_AppManager_load, this); -#else - m_httpServer = new net::CHttpServer(atoi(getFreeListeningPort()), strAppRootPath); m_httpServer->register_uri("/system/geolocation", rubyext::CGeoLocation::callback_geolocation); m_httpServer->register_uri("/system/syncdb", callback_syncdb); m_httpServer->register_uri("/system/redirect_to", callback_redirect_to); m_httpServer->register_uri("/system/map", callback_map); m_httpServer->register_uri("/system/shared", callback_shared); m_httpServer->register_uri("/AppManager/loader/load", callback_AppManager_load); m_httpServer->register_uri("/system/getrhomessage", callback_getrhomessage); m_httpServer->register_uri("/system/activateapp", callback_activateapp); -#endif + m_httpServer->register_uri("/system/loadserversources", callback_loadserversources); } const char* CRhodesApp::getFreeListeningPort() { if ( m_strListeningPorts.length() > 0 ) @@ -456,18 +403,27 @@ m_currentTabIndex = 0; m_strHomeUrl = "http://localhost:"; m_strHomeUrl += getFreeListeningPort(); - m_strBlobsDirPath = getRhoRootPath() + "apps/public/db-files"; + m_strBlobsDirPath = getRhoRootPath() + "db/db-files"; + m_strDBDirPath = getRhoRootPath() + "db"; m_strLoadingPagePath = "file://" + getRhoRootPath() + "apps/app/loading.html"; m_strLoadingPngPath = getRhoRootPath() + "apps/app/loading.png"; } +String CRhodesApp::resolveDBFilesPath(const String& strFilePath) +{ + if ( String_startsWith(strFilePath, getRhoRootPath()) ) + return strFilePath; + + return CFilePath::join(getRhoRootPath(), strFilePath); +} + void CRhodesApp::keepLastVisitedUrl(String strUrl) { - LOG(INFO) + "Current URL: " + strUrl; + //LOG(INFO) + "Current URL: " + strUrl; m_currentUrls[m_currentTabIndex] = canonicalizeRhoUrl(strUrl); if ( RHOCONF().getBool("KeepTrackOfLastVisitedPage") ) { @@ -481,10 +437,18 @@ RHOCONF().setString("LastVisitedPage",strUrl); RHOCONF().saveToFile(); } } +void CRhodesApp::setAppBackUrl(const String& url) +{ + if ( url.length() > 0 ) + m_strAppBackUrl = canonicalizeRhoUrl(url); + else + m_strAppBackUrl = ""; +} + const String& CRhodesApp::getStartUrl() { m_strStartUrl = canonicalizeRhoUrl( RHOCONF().getString("start_path") ); return m_strStartUrl; } @@ -519,58 +483,40 @@ return m_strRhobundleReloadUrl; } void CRhodesApp::navigateToUrl( const String& strUrl) { - webview_navigate(const_cast<char*>(strUrl.c_str()), 0); + rho_webview_navigate(strUrl.c_str(), 0); } +void CRhodesApp::navigateBack() +{ + rho::String strAppUrl = getAppBackUrl(); + + if ( strAppUrl.length() > 0 ) + rho_webview_navigate(strAppUrl.c_str(), 0); + else if ( strcasecmp(getCurrentUrl().c_str(),getStartUrl().c_str()) != 0 ) + rho_webview_navigate_back(); +} + String CRhodesApp::canonicalizeRhoUrl(const String& strUrl) { if (strUrl.length() == 0 ) return m_strHomeUrl; if ( strncmp("http://", strUrl.c_str(), 7 ) == 0 || + strncmp("https://", strUrl.c_str(), 8 ) == 0 || + strncmp("javascript:", strUrl.c_str(), 11 ) == 0 || strncmp("mailto:", strUrl.c_str(), 7) == 0 || - strncmp("tel:", strUrl.c_str(), 4) == 0) + strncmp("tel:", strUrl.c_str(), 4) == 0 || + strncmp("wtai:", strUrl.c_str(), 5) == 0 + ) return strUrl; return CFilePath::join(m_strHomeUrl,strUrl); } -void CRhodesApp::addViewMenuItem( const String& strLabel, const String& strLink ) -{ - if ( strLabel.length() == 0 ) - return; - - synchronized(m_mxViewMenuItems) - { - m_hashViewMenuItems.put(strLabel, strLink); - - if ( strcasecmp( strLabel.c_str(), "back" )==0 && strcasecmp( strLink.c_str(), "back" )!=0 ) - m_strAppBackUrl = canonicalizeRhoUrl(strLink); - } -} - -extern "C" void -menu_iter(const char* szLabel, const char* szLink, void* pThis) -{ - ((CRhodesApp*)pThis)->addViewMenuItem(szLabel, szLink ); -} - -void CRhodesApp::setViewMenu(unsigned long valMenu) -{ - { - synchronized(m_mxViewMenuItems) - - m_hashViewMenuItems.clear(); - m_strAppBackUrl=""; - } - - rho_ruby_enum_strhash(valMenu, menu_iter, this); -} - boolean CRhodesApp::sendLog() { String strDevicePin = rho::sync::CClientRegister::getInstance() ? rho::sync::CClientRegister::getInstance()->getDevicePin() : ""; String strClientID = rho::sync::CSyncThread::getSyncEngine().loadClientID(); @@ -579,11 +525,19 @@ strLogUrl = RHOCONF().getPath("syncserver"); String strQuery = strLogUrl + "client_log?" + "client_id=" + strClientID + "&device_pin=" + strDevicePin + "&log_name=" + RHOCONF().getString("logname"); - NetResponse( resp, getNet().pushFile( strQuery, LOGCONF().getLogFilePath(), &(rho::sync::CSyncThread::getSyncEngine()), null ) ); + net::CMultipartItem oItem; + oItem.m_strFilePath = LOGCONF().getLogFilePath(); + oItem.m_strContentType = "application/octet-stream"; + + boolean bOldSaveToFile = LOGCONF().isLogToFile(); + LOGCONF().setLogToFile(false); + NetResponse( resp, getNet().pushMultipartData( strQuery, oItem, &(rho::sync::CSyncThread::getSyncEngine()), null ) ); + LOGCONF().setLogToFile(bOldSaveToFile); + if ( !resp.isOK() ) { LOG(ERROR) + "send_log failed : network error"; return false; } @@ -624,13 +578,104 @@ return rho_ruby_get_NIL(); return pCallbackObject->getObjectValue(); } +void CRhodesApp::setPushNotification(String strUrl, String strParams ) +{ + synchronized(m_mxPushCallback) + { + m_strPushCallback = canonicalizeRhoUrl(strUrl); + m_strPushCallbackParams = strParams; + } } + +boolean CRhodesApp::callPushCallback(String strData) +{ + synchronized(m_mxPushCallback) + { + if ( m_strPushCallback.length() == 0 ) + return false; + + String strBody = "status=ok&message="; + net::URI::urlEncode(strData, strBody); + strBody += "&rho_callback=1"; + if ( m_strPushCallbackParams.length() > 0 ) + strBody += "&" + m_strPushCallbackParams; + + common::CAutoPtr<net::INetRequest> pNetRequest = m_ptrFactory->createNetRequest(); + NetResponse(resp,pNetRequest->pushData( m_strPushCallback, strBody, null )); + if (!resp.isOK()) + LOG(ERROR) + "Push notification failed. Code: " + resp.getRespCode() + "; Error body: " + resp.getCharData(); + else + { + const char* szData = resp.getCharData(); + return !(szData && strcmp(szData,"rho_push") == 0); + } + } + + return true; } +void CRhodesApp::setScreenRotationNotification(String strUrl, String strParams) +{ + synchronized(m_mxScreenRotationCallback) + { + m_strScreenRotationCallback = canonicalizeRhoUrl(strUrl); + m_strScreenRotationCallbackParams = strParams; + } +} + +void CRhodesApp::callScreenRotationCallback(int width, int height, int degrees) +{ + synchronized(m_mxScreenRotationCallback) + { + if (m_strScreenRotationCallback.length() == 0) + return; + + String strBody = "rho_callback=1"; + + strBody += "&width="; strBody += convertToStringA(width); + strBody += "&heigth="; strBody += convertToStringA(height); + strBody += "&degrees="; strBody += convertToStringA(degrees); + + if ( m_strScreenRotationCallbackParams.length() > 0 ) + strBody += "&" + m_strPushCallbackParams; + + common::CAutoPtr<net::INetRequest> pNetRequest = m_ptrFactory->createNetRequest(); + NetResponse(resp, pNetRequest->pushData( m_strScreenRotationCallback, strBody, null)); + + if (!resp.isOK()) { + LOG(ERROR) + "Screen rotation notification failed. Code: " + resp.getRespCode() + "; Error body: " + resp.getCharData(); + } + } +} + +void CRhodesApp::loadUrl(String url) +{ + boolean callback = false; + if (url.size() >= 9 && url.substr(0, 9) == "callback:") + { + callback = true; + url = url.substr(9); + } + char *s = rho_http_normalizeurl(url.c_str()); + url = s; + free(s); + if (callback) + { + common::CAutoPtr<net::INetRequest> pNetRequest = m_ptrFactory->createNetRequest(); + NetResponse(resp, pNetRequest->pullData( url, null )); + (void)resp; + } + else + navigateToUrl(url); +} + +} //namespace common +} //namespace rho + extern "C" { unsigned long rho_rhodesapp_GetCallbackObject(int nIndex) { return RHODESAPP().getCallbackObject(nIndex); @@ -647,29 +692,10 @@ free(data); } void rho_http_redirect( void* httpContext, const char* szUrl) { -#if !defined(RHO_HTTPD_COMMON_IMPL) - struct shttpd_arg *arg = (struct shttpd_arg *)httpContext; - - shttpd_printf(arg, "%s", "HTTP/1.1 301 Moved Permanently\r\n"); - shttpd_printf(arg, "Location: %s\r\n", szUrl ); - shttpd_printf(arg, "%s", "Content-Length: 0\r\n"); - shttpd_printf(arg, "%s", "Connection: close\r\n"); -//#ifndef OS_MACOSX - shttpd_printf(arg, "%s", "Pragma: no-cache\r\n" ); - shttpd_printf(arg, "%s", "Cache-Control: must-revalidate\r\n" ); - shttpd_printf(arg, "%s", "Cache-Control: no-cache\r\n" ); - shttpd_printf(arg, "%s", "Cache-Control: no-store\r\n" ); - shttpd_printf(arg, "%s", "Expires: 0\r\n" ); -//#endif - - shttpd_printf(arg, "%s", "Content-Type: text/plain\r\n\r\n"); - - arg->flags |= SHTTPD_END_OF_OUTPUT; -#else HttpHeaderList headers; headers.push_back(HttpHeader("Location", szUrl)); headers.push_back(HttpHeader("Content-Length", 0)); headers.push_back(HttpHeader("Pragma", "no-cache")); headers.push_back(HttpHeader("Cache-Control", "must-revalidate")); @@ -678,63 +704,27 @@ headers.push_back(HttpHeader("Expires", 0)); headers.push_back(HttpHeader("Content-Type", "text/plain")); CHttpServer *serv = (CHttpServer *)httpContext; serv->send_response(serv->create_response("301 Moved Permanently", headers)); -#endif } void rho_http_senderror(void* httpContext, int nError, const char* szMsg) { -#if !defined(RHO_HTTPD_COMMON_IMPL) - struct shttpd_arg *arg = (struct shttpd_arg *)httpContext; - - shttpd_printf(arg, "%s", "HTTP/1.1 %d %s\r\n", nError, szMsg); - arg->flags |= SHTTPD_END_OF_OUTPUT; -#else char buf[30]; snprintf(buf, sizeof(buf), "%d", nError); rho::String reason = buf; reason += " "; reason += szMsg; CHttpServer *serv = (CHttpServer *)httpContext; serv->send_response(serv->create_response(reason)); -#endif } void rho_http_sendresponse(void* httpContext, const char* szBody) { -#if !defined(RHO_HTTPD_COMMON_IMPL) - struct shttpd_arg *arg = (struct shttpd_arg *)httpContext; - unsigned long nBodySize = strlen(szBody); - - shttpd_printf(arg, "%s", "HTTP/1.1 200 OK\r\n"); - shttpd_printf(arg, "Content-Length: %lu\r\n", nBodySize ); - shttpd_printf(arg, "%s", "Connection: close\r\n"); -#ifndef OS_MACOSX - shttpd_printf(arg, "%s", "Pragma: no-cache\r\n" ); - shttpd_printf(arg, "%s", "Cache-Control: no-cache\r\n" ); - shttpd_printf(arg, "%s", "Expires: 0\r\n" ); -#else - const char *fmt = "%a, %d %b %Y %H:%M:%S GMT"; - char date[64], lm[64]; - time_t _current_time = time(0); - strftime(date, sizeof(date), fmt, localtime(&_current_time)); - strftime(lm, sizeof(lm), fmt, localtime(&_current_time)); - - shttpd_printf(arg, "Date: %s\r\n", date); - shttpd_printf(arg, "Last-Modified: %s\r\n", lm); - shttpd_printf(arg, "Etag: \"%lx.%lx\"\r\n", (unsigned long) _current_time, nBodySize); -#endif - - shttpd_printf(arg, "%s", "Content-Type: text/html; charset=ISO-8859-4\r\n\r\n"); - shttpd_printf(arg, "%s", szBody ); - - arg->flags |= SHTTPD_END_OF_OUTPUT; -#else size_t nBodySize = strlen(szBody); HttpHeaderList headers; headers.push_back(HttpHeader("Content-Length", nBodySize)); headers.push_back(HttpHeader("Pragma", "no-cache")); @@ -752,11 +742,10 @@ headers.push_back(HttpHeader("Last-Modified", lm)); headers.push_back(HttpHeader("Etag", etag)); CHttpServer *serv = (CHttpServer *)httpContext; serv->send_response(serv->create_response("200 OK", headers, szBody)); -#endif } int rho_http_snprintf(char *buf, size_t buflen, const char *fmt, ...) { va_list ap; @@ -829,10 +818,15 @@ const char* rho_rhodesapp_getblobsdirpath() { return RHODESAPP().getBlobsDirPath().c_str(); } +void rho_rhodesapp_navigate_back() +{ + RHODESAPP().navigateBack(); +} + void rho_rhodesapp_callCameraCallback(const char* strCallbackUrl, const char* strImagePath, const char* strError, int bCancel ) { RHODESAPP().callCameraCallback(strCallbackUrl, strImagePath, strError, bCancel != 0); } @@ -840,25 +834,45 @@ void rho_rhodesapp_callDateTimeCallback(const char* strCallbackUrl, long lDateTime, const char* szData, int bCancel ) { RHODESAPP().callDateTimeCallback(strCallbackUrl, lDateTime, szData, bCancel != 0); } +void rho_rhodesapp_callPopupCallback(const char *strCallbackUrl, const char *id, const char *title) +{ + RHODESAPP().callPopupCallback(strCallbackUrl, id, title); +} + void rho_rhodesapp_callAppActiveCallback(int nActive) { RHODESAPP().callAppActiveCallback(nActive!=0); } void rho_rhodesapp_setViewMenu(unsigned long valMenu) { - RHODESAPP().setViewMenu(valMenu); + RHODESAPP().getAppMenu().setAppMenu(valMenu); } const char* rho_rhodesapp_getappbackurl() { return RHODESAPP().getAppBackUrl().c_str(); } +int rho_rhodesapp_callPushCallback(const char* szData) +{ + if ( !rho::common::CRhodesApp::getInstance() ) + return 1; + + return RHODESAPP().callPushCallback(szData?szData:"") ? 1 : 0; +} + +void rho_rhodesapp_callScreenRotationCallback(int width, int height, int degrees) +{ + if ( !rho::common::CRhodesApp::getInstance() ) + return; + RHODESAPP().callScreenRotationCallback(width, height, degrees); +} + const char* rho_ruby_getErrorText(int nError) { return RHODESAPP().getRhoMessage( nError, "").c_str(); } @@ -953,7 +967,52 @@ rho::common::CAutoPtr<rho::common::IRhoClassFactory> factory = rho::common::createClassFactory(); rho::common::CAutoPtr<rho::net::INetRequest> request = factory->createNetRequest(); request->pullData(url, null); } +int rho_unzip_file(const char* szZipPath) +{ +#ifdef UNICODE + rho::StringW strZipPathW; + rho::common::convertToStringW(szZipPath, strZipPathW); + HZIP hz = OpenZipFile(strZipPathW.c_str(), ""); + if ( !hz ) + return 0; + + // Set base for unziping + SetUnzipBaseDir(hz, rho::common::convertToStringW(RHODESAPP().getDBDirPath()).c_str() ); +#else + HZIP hz = OpenZipFile(szZipPath, ""); + if ( !hz ) + return 0; + + // Set base for unziping + SetUnzipBaseDir(hz, RHODESAPP().getDBDirPath().c_str() ); +#endif + + ZIPENTRY ze; + ZRESULT res = 0; + // Get info about the zip + // -1 gives overall information about the zipfile + res = GetZipItem(hz,-1,&ze); + int numitems = ze.index; + + // Iterate through items and unzip them + for (int zi = 0; zi<numitems; zi++) + { + // fetch individual details, e.g. the item's name. + res = GetZipItem(hz,zi,&ze); + if ( res == ZR_OK ) + res = UnzipItem(hz, zi, ze.name); + } + + CloseZip(hz); + + return res == ZR_OK ? 1 : 0; } +void rho_rhodesapp_load_url(const char *url) +{ + RHODESAPP().loadUrl(url); +} + +} //extern "C"