int main(int argc, char * argv[])
{
    try
    {
        string resource;
        string type;
        string resourceEntity;
        string objectId;
        string outputPrefix;
        bool returnUrl;
        vector<string> resourceSets;
        bool ignoreMalformedHeaders;
        
        Options options;
        options.descriptions.add_options()
            ("resource,r", po::value<string>(&resource)
             ->default_value("Property"), "Object resource")
            ("type", po::value<string>(&type)
             ->default_value("Photo"), "Object type")
            ("output-prefix", po::value<string>(&outputPrefix)
             ->default_value(""), "Output file prefix")
            ("resource-set", po::value< vector<string> >(&resourceSets),
             "Resource sets (e.g. 'resource-id' or 'resource-id:#,#'))")
            ("return-url", po::value<bool>(&returnUrl)
             ->default_value(false), "Return the URL to the object (true or false)")
            ("ignore-malformed-headers", po::value<bool>(&ignoreMalformedHeaders)
             ->default_value(false), "Ignore malformed headers (true or false)")
            ;
        if (!options.ParseCommandLine(argc, argv))
        {
            return 1;
        }
        
        if (resourceSets.size() == 0)
        {
            resourceSets.push_back("1");
        }

        RetsSessionPtr session = options.RetsLogin();
        if (!session)
        {
            cout << "Login failed\n";
            return -1;
        }
    
        GetObjectRequest getObjectRequest(resource, type);
    
        vector<string>::const_iterator i;
        for (i = resourceSets.begin(); i != resourceSets.end(); i++)
        {
            vector<string> resourceSet;
            ba::split(resourceSet, *i, ba::is_any_of(":"));
            if (resourceSet.size() == 1)
            {
                getObjectRequest.AddAllObjects(resourceSet[0]);
            }
            else if (resourceSet.size() == 2)
            {
                vector<string> ids;
                ba::split(ids, resourceSet[1], ba::is_any_of(","));
                vector<string>::const_iterator idString;
                for (idString = ids.begin(); idString != ids.end();
                     idString++)
                {
                    int id  = lexical_cast<int>(*idString);
                    getObjectRequest.AddObject(resourceSet[0], id);
                }
            }
        }
        getObjectRequest.SetLocation(returnUrl);
        getObjectRequest.SetIgnoreMalformedHeaders(ignoreMalformedHeaders);
    
        GetObjectResponseAPtr getObjectResponse =
            session->GetObject(&getObjectRequest);
    
        StringMap contentTypeSuffixes;
        contentTypeSuffixes["image/jpeg"] = "jpg";
        contentTypeSuffixes["text/xml"] = "xml";
        ObjectDescriptor * objectDescriptor;
        while ((objectDescriptor = getObjectResponse->NextObject()))
        {
            int retsReplyCode = objectDescriptor->GetRetsReplyCode();
            string retsReplyText = objectDescriptor->GetRetsReplyText();
            
            string objectKey = objectDescriptor->GetObjectKey();
            int objectId = objectDescriptor->GetObjectId();
            string contentType = objectDescriptor->GetContentType();
            string description = objectDescriptor->GetDescription();
            string location = objectDescriptor->GetLocationUrl();
            
            if (objectDescriptor->GetWildIndicator())
                cout << objectKey << " object #: *";
            else
                cout << objectKey << " object #" << objectId;
            if (!description.empty())
                cout << ", description: " << description;
            if (!location.empty())
                cout << ", location: " << location;
            if (retsReplyCode)
                cout << ", **** " << retsReplyCode << ": " << retsReplyText;
                
            cout << endl;
            
            string suffix = contentTypeSuffixes[contentType];
            string outputFileName = outputPrefix + objectKey + "-" +
                lexical_cast<string>(objectId) + "." + suffix;
            /*
             * Only save the object if there was no error and we're not
             * using the location option.
             */
            if (retsReplyCode == 0 && location.empty())
            {
                ofstream outputStream(outputFileName.c_str());
                istreamPtr inputStream = objectDescriptor->GetDataStream();
                readUntilEof(inputStream, outputStream);
            }
        }
    
        session->Logout();
    }
    catch (RetsException & e)
    {
        e.PrintFullReport(cerr);
    }
    catch (std::exception & e)
    {
        cerr << e.what() << endl;
    }
}
int main(int argc, char * argv[])
{
    try
    {
        Options options;
        options.descriptions.add_options()
            ("show-urls", "Show all the capability URLs")
            ;

        if (!options.ParseCommandLine(argc, argv))
        {
            return 0;
        }

        RetsSessionPtr session = options.RetsLogin();
        if (!session)
        {
            cout << "Login failed\n";
            return -1;
        }
        cout << "Logged in\n";
        
        LoginResponse * login = session->GetLoginResponse();
        CapabilityUrls * urls = session->GetCapabilityUrls();

        cout << "Member name: " << login->GetMemberName() << endl;
        cout << "Search URL: " << urls->GetSearchUrl() << endl;        
        cout << "Action:\n" << session->GetAction() << endl;
        
        if (session->GetDetectedRetsVersion() >= RETS_1_8)
        {
            try
            {
                cout << "User ID:"                          << login->GetUserID() << endl;
                cout << "User Class: "                      << login->GetUserClass() << endl;
                cout << "User Level: "                      << login->GetUserLevel() << endl;
                cout << "Agent Code: "                      << login->GetAgentCode() << endl;
                if (options.count("verbose"))
                {
                    cout << "Broker Code: "                 << login->GetBrokerCode() << endl;
                    cout << "Broker Branch: "               << login->GetBrokerBranch() << endl;
                    cout << "Metadata ID: "                 << login->GetMetadataID() << endl;
                    cout << "Metadata Version: "            << login->GetMetadataVersion() << endl;
                    cout << "Metadata Timestamp: "          << login->GetMetadataTimestamp() << endl;
                    cout << "Min Metadata Timestamp: "      << login->GetMinMetadataTimestamp() << endl;
                    cout << "Balance: "                     << login->GetBalance() << endl;
                    cout << "Timeout Seconds: "             << login->GetTimeout() << endl;
                    cout << "Password Expiration: "         << login->GetPasswordExpire() << endl;
                    cout << "Password Expiration Warn: "    << login->GetWarnPasswordExpirationDays() << endl;
                    cout << "OfficeList: "                  << login->GetOfficeList() << endl;
                    cout << "Standard Names Version: "      << login->GetStandardNamesVersion() << endl;
                    cout << "Vendor Name: "                 << login->GetVendorName() << endl;
                    cout << "Server Product Name: "         << login->GetServerProductName() << endl;
                    cout << "Operator Name: "               << login->GetOperatorName() << endl;
                    cout << "Role Name: "                   << login->GetRoleName() << endl;
                    cout << "Support Contact Information: " << login->GetSupportContactInformation() << endl;
                }
            }
            catch (RetsException & e)
            {
               /*
                * The ServerInformation Transaction is not supported.
                * Continue silently.
                */
            }
        }

        if (options.count("show-urls"))
        {
            /*
             * Action and Search URLs unconditionally shown above.
             */
            cout << "Change Password URL: " << urls->GetChangePasswordUrl() << endl;
            cout << "GetObject URL: " << urls->GetGetObjectUrl() << endl;
            cout << "Login Complete URL: " << urls->GetLoginCompleteUrl() << endl;
            cout << "Logout URL: " << urls->GetLogoutUrl() << endl;
            cout << "GetMetadata URL: " << urls->GetGetMetadataUrl() << endl;
            cout << "ServerInformation URL: " << urls->GetServerInformationUrl() << endl;
            cout << "Update URL: " << urls->GetUpdateUrl() << endl;
            if (session->GetDetectedRetsVersion() >= RETS_1_8)
            {
                cout << "Payload List URL: " << urls->GetPayloadListUrl() << endl;
            }
            cout << endl;
        }
        
        if (session->GetDetectedRetsVersion() == RETS_1_7)
        {
            try
            {
                ServerInformationResponseAPtr serverInfo = session->GetServerInformation();
                
                if (serverInfo.get())
                {
                    StringVector parameters = serverInfo->GetParameters();
                    StringVector::const_iterator i;
                    for (i = parameters.begin(); i != parameters.end(); i++)
                    {
                        if (i->empty())
                        {
                            continue;
                        }
                        cout << *i << ": " << serverInfo->GetValue(*i) << endl;
                    }
                }
            }
            catch (RetsException & e)
            {
               /*
                * The ServerInformation Transaction is not supported.
                * Continue silently.
                */
            }
        }

        if (session->GetDetectedRetsVersion() >= RETS_1_8)
        {
            try
            {
                PayloadListResultSetAPtr payloadList = session->GetPayloadList("");
                    
                if (options.count("verbose"))
                {
                    cout << setw(15) << "Class" << ": "
                    << setw(0) << payloadList->GetPayloadClass() << endl;
                    cout << setw(15) << "Resource" << ": "
                    << setw(0) << payloadList->GetPayloadResource() << endl;
                    cout << setw(15) << "Date" << ": "
                    << setw(0) << payloadList->GetPayloadDate() << endl;
                    cout << setw(15) << "Version" << ": "
                    << setw(0) << payloadList->GetPayloadVersion() << endl << endl;
                }
                
                while (payloadList->HasNext())
                {
                    StringVector columns = payloadList->GetColumns();
                    StringVector::const_iterator i;
                    for (i = columns.begin(); i != columns.end(); i++)
                    {
                        string column = *i;
                        cout << setw(15) << column << ": "
                        << setw(0) << payloadList->GetString(column) << endl;
                    }
                    cout << endl;                    
                }
            }
            catch (RetsException & e)
            {
                /*
                 * The GetPayloadList Transaction is not supported.
                 */
                cout << e.what() << endl;
            }
        }
        
        LogoutResponseAPtr logout = session->Logout();
        cout << "Logged out\n";
        if (logout.get())
        {
            cout << "Billing information: " << logout->GetBillingInfo()
                 << endl;
            cout << "Connect time: " << logout->GetConnectTime() << endl;
            cout << "Message: " << logout->GetLogoutMessage() << endl;
        }
    }
    catch (RetsException & e)
    {
        e.PrintFullReport(cerr);
        return 1;
    }
    catch (exception & e)
    {
        cerr << e.what() << endl;
        return 2;
    }
    return 0;
}
int main(int argc, char * argv[])
{
    try
    {
        Options options;
        if (!options.ParseCommandLine(argc, argv))
        {
            return 0;
        }

        RetsSessionPtr session = options.RetsLogin();
        if (!session)
        {
            cout << "Login failed\n";
            return -1;
        }

        if (session->GetDetectedRetsVersion() != session->GetRetsVersion())
        {
            cout << "** Warning, requested RETS version \"" 
                 << session->RetsVersionToString(session->GetRetsVersion())
                 << "\", got version \""
                 << session->RetsVersionToString(session->GetDetectedRetsVersion())
                 << "\" ** " << endl;
        }
        
        if (session->GetDetectedRetsVersion() == RETS_1_7)
        {
            try
            {
                ServerInformationResponseAPtr serverInfo = session->GetServerInformation();
                
                if (serverInfo.get())
                {
                    StringVector parameters = serverInfo->GetParameters();
                    StringVector::const_iterator i;
                    for (i = parameters.begin(); i != parameters.end(); i++)
                    {
                        if (i->empty())
                        {
                            continue;
                        }
                        cout << *i << ": " << serverInfo->GetValue(*i) << endl;
                    }
                }
            }
            catch (RetsException & e)
            {
               /*
                * The ServerInformation Transaction is not supported.
                * Continue silently.
                */
            }
        }

        RetsMetadata * metadata = session->GetMetadata();
        dumpSystem(metadata);
        dumpAllForeignKeys(metadata);
        dumpAllResources(metadata);

        session->Logout();
    }
    catch (RetsException & e)
    {
        e.PrintFullReport(cout);
        return 1;
    }
    catch (exception & e)
    {
        cout << e.what() << endl;
        return 2;
    }
    return 0;
}