<commit_before>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Connects to a Watcher server and writes the event stream to a KML file suitable for use
 * with Google Earth.
 *
 * @author michael.elkins@cobham.com
 */

#include <unistd.h>
#include <getopt.h>
#include <stdint.h>

#include <cassert>
#include <iostream>
#include <cstdlib>

#include "logger.h"
#include "initConfig.h"
#include "singletonConfig.h"
#include "libwatcher/messageStream.h"
#include "libwatcher/watcherGraph.h"
#include "libwatcher/playbackTimeRange.h"

#define TOOL_NAME "earthWatcher"
DECLARE_GLOBAL_LOGGER(TOOL_NAME);

using namespace watcher;

void write_kml(const WatcherGraph& graph, const std::string& outputFile); // kml.cc

namespace watcher {
    float LayerPadding = 10;
    float Lonoff = 0.0;
    float Latoff = 0.0;
    float Altoff = 0.0;
}

namespace {

//arguments to getopt_long()
const option OPTIONS[] = {
    { "latoff", required_argument, 0, 'a' },
    { "altoff", required_argument, 0, 'A' },
    { "config", required_argument, 0, 'c' },
    { "help", no_argument, 0, 'h' },
    { "output", required_argument, 0, 'o' },
    { "lonoff", required_argument, 0, 'O' },
    { "refresh", required_argument, 0, 'r' },
    { "seek", required_argument, 0, 'S' },
    { "server", required_argument, 0, 's' },
    { "speed", required_argument, 0, 'd' },
    { 0, 0, 0, 0 }
};

const char *CONFIG_FILE = TOOL_NAME ".cfg";
const char *OUTPUT_FILE = "watcher.kml";
const char *PROPERTY_FILE = TOOL_NAME ".log.properties";
const char *DEFAULT_HOST = "127.0.0.1";
const unsigned int DEFAULT_REFRESH = 1; // SECONDS

void usage()
{
    const char *SEP = "\t\t";   // separator for argument/description columns

    std::cout << "usage: earthWatcher [ -h ] [ -c FILE ]\n"
        "  -a, --latoff OFF" << SEP << "translate GPS coordinates relative to a given latitude\n"
        "  -A, --altoff OFF" << SEP << "translate GPS coordinates relative to the given altitude\n"
        "  -c, --config FILE" << SEP << "specify a configuration file (default: " << CONFIG_FILE << ")\n"
        "  -d, --speed SPEED" << SEP << "specify the event playback rate (default: 1.0)\n"
        "  -h, --help\t" << SEP << "display this help message\n"
        "  -o, --output FILE" << SEP << "specifies the output KML file (default: " << OUTPUT_FILE << ")\n"
        "  -O, --lonoff OFF" << SEP << "translate GPS coordinates relative to a given longitude\n"
        "  -r, --refresh SECS" << SEP << "write the the output every SECS seconds (default: " << DEFAULT_REFRESH << ")\n"
        "  -s, --server HOST" << SEP << "connect to the watcher server on the given host (default: " << DEFAULT_HOST << ")\n"
        "  -S, --seek POS" << SEP << "start event playback at timestamp POS (default: -1)\n"
        "\tPOS may be specified relative to the first and last timestamps in the Watcher database by prefixing the offset with + or -\n"
        "\tExample: +5000 means 5 seconds after the first event in the database.\n"
        << std::endl;
}

} // end namespace

int main(int argc, char **argv)
{
    TRACE_ENTER();

    const char *output_file = 0;
    Timestamp start_timestamp = -1 ; // default to EOF (live playback)
    unsigned int refresh = DEFAULT_REFRESH;
    float speed = 1.0;
    bool relativeTS = false; // when true, start_timestamp is relative to first or last event in the Watcher DB
    unsigned int args = 0;
    enum {
        argLayerPadding = (1<<0),
        argLonoff = (1<<1),
        argLatoff = (1<<2),
        argAltoff = (1<<3),
        argOutputFile = (1<<4),
        argServerName = (1<<5)
    };
    std::string outputFile(OUTPUT_FILE);
    std::string serverName(DEFAULT_HOST);

    for (int i; (i = getopt_long(argc, argv, "a:A:hc:d:o:O:r:S:", OPTIONS, 0)) != -1; ) {
        switch (i) {
            case 'c':
                break; //handled by initConfig()

            case 'a':
                Latoff = atof(optarg);
                args |= argLatoff;
                break;

            case 'A':
                Altoff = atof(optarg);
                args |= argAltoff;
                break;

            case 'd':
                speed = atoi(optarg);
                break;

            case 'o': // output-file
                outputFile = optarg;
                args |= argOutputFile;
                break;

            case 'O':
                Lonoff = atoi(optarg);
                args |= argLonoff;
                break;

            case 'r':
                refresh = atoi(optarg);
                break;

            case 'S':
                relativeTS = (optarg[0] == '+' || optarg[0] == '-'); // when +/- is prefix, seek relative to starting/ending event
                start_timestamp = atol(optarg);
                if (start_timestamp == -1)
                    relativeTS = false; // special case for EOF value
                break;

            case 's':
                serverName = optarg;
                args |= argServerName;

            case 'h':
            default:
                usage();
                TRACE_EXIT_RET(EXIT_SUCCESS);
                return EXIT_SUCCESS;
                break;
        }
    }

    libconfig::Config& config = SingletonConfig::instance();
    SingletonConfig::lock();
    std::string configFilename; //filled by initConfig()
    if (! watcher::initConfig(config, argc, argv, configFilename))
        std::cout << "Configuration file not found. Creating new configuration file and using default runtime values." << std::endl;
    SingletonConfig::unlock();

    std::string logConf(PROPERTY_FILE);
    std::string service("watcherd");
    struct {
        const char *configName;
        std::string *value;
        unsigned int bit;
    } ConfigString[] = {
        { "logPropertiesFile", &logConf, 0 },
        { "server", &serverName, argServerName },
        { "service", &service, 0 },
        { "outputFile", &outputFile, argOutputFile },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigString[i].configName != 0; ++i) {
        if ((args & ConfigString[i].bit) == 0 && !config.lookupValue(ConfigString[i].configName, *ConfigString[i].value)) {
            LOG_INFO("'" << ConfigString[i].configName << "' not found in the configuration file, using default: " << *ConfigString[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigString[i].configName, libconfig::Setting::TypeString) = *ConfigString[i].value;
        }
    }

    LOAD_LOG_PROPS(logConf);
    LOG_INFO("Logger initialized from file \"" << logConf << "\"");

    struct {
        const char *configName;
        float* value;
        unsigned int bit;
    } ConfigFloat[] = {
        { "layerPadding", &LayerPadding, argLayerPadding },
        { "lonOff", &Lonoff, argLonoff },
        { "latOff", &Latoff, argLatoff },
        { "altOff", &Altoff, argAltoff },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigFloat[i].configName != 0; ++i) {
        if ((args & ConfigFloat[i].bit) == 0 && !config.lookupValue(ConfigFloat[i].configName, *ConfigFloat[i].value)) {
            LOG_INFO("'" << ConfigFloat[i].configName << "' not found in the configuration file, using default: " << *ConfigFloat[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigFloat[i].configName, libconfig::Setting::TypeFloat) = *ConfigFloat[i].value;
        }
    }

    // open a message stream of live events for now
    MessageStreamPtr ms(MessageStream::createNewMessageStream(serverName, service, start_timestamp, speed));
    if (!ms) {
        LOG_FATAL("Unable to create new message stream to server \"" << serverName << "\" using service (or port) \"" << service);
        TRACE_EXIT_RET(EXIT_FAILURE);
        return EXIT_FAILURE;
    }

    if (relativeTS) {
        ms->getMessageTimeRange();
    } else {
        LOG_INFO("Starting event playback");
        ms->startStream();
    }

    srandom(time(0));//we use random() to select the icon below
    WatcherGraph graph;

    unsigned int messageNumber = 0;
    MessagePtr mp;
    time_t last_output = 0; // counter to allow for writing the kml file on a fixed time interval
    bool changed = false;
    bool needTimeRange = relativeTS;

    LOG_INFO("Waiting for events ");
    while (ms->getNextMessage(mp)) {
        // std::cout << "Message #" << (++messageNumber) << ": " << *mp << std::endl;

        if (needTimeRange) {
            PlaybackTimeRangeMessagePtr trp(boost::dynamic_pointer_cast<PlaybackTimeRangeMessage>(mp));
            if (trp.get() != 0) {
                LOG_INFO( "first offset=" << trp->min_ << ", last offset=" << trp->max_ );
                needTimeRange = false;

                Timestamp off = start_timestamp + (( start_timestamp >= 0 ) ? trp->min_ : trp->max_ );
                ms->setStreamTimeStart(off);

                LOG_INFO("Starting event playback");
                ms->startStream();

                continue;
            }
        }

        changed |= graph.updateGraph(mp);

        if (changed) {
            time_t now = time(0);
            if (now - last_output >= refresh) {
                graph.doMaintanence(); // expire stale links
                LOG_DEBUG("writing kml file");
                last_output = now;
                write_kml(graph, outputFile);
            }
            changed = false; // reset flag
        }
    }

    // Save any configuration changes made during the run.
    LOG_INFO("Saving last known configuration to " << configFilename);
    SingletonConfig::lock();
    config.writeFile(configFilename.c_str());

    TRACE_EXIT_RET(0);
    return 0;
}
<commit_msg>Fixed floating point truncation in --speed and --lonOff arguments.<commit_after>/* Copyright 2009 SPARTA, Inc., dba Cobham Analytic Solutions
 *
 * This file is part of WATCHER.
 *
 *     WATCHER is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     WATCHER is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with Watcher.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Connects to a Watcher server and writes the event stream to a KML file suitable for use
 * with Google Earth.
 *
 * @author michael.elkins@cobham.com
 */

#include <unistd.h>
#include <getopt.h>
#include <stdint.h>

#include <cassert>
#include <iostream>
#include <cstdlib>

#include "logger.h"
#include "initConfig.h"
#include "singletonConfig.h"
#include "libwatcher/messageStream.h"
#include "libwatcher/watcherGraph.h"
#include "libwatcher/playbackTimeRange.h"

#define TOOL_NAME "earthWatcher"
DECLARE_GLOBAL_LOGGER(TOOL_NAME);

using namespace watcher;

void write_kml(const WatcherGraph& graph, const std::string& outputFile); // kml.cc

namespace watcher {
    float LayerPadding = 10;
    float Lonoff = 0.0;
    float Latoff = 0.0;
    float Altoff = 0.0;
}

namespace {

//arguments to getopt_long()
const option OPTIONS[] = {
    { "latoff", required_argument, 0, 'a' },
    { "altoff", required_argument, 0, 'A' },
    { "config", required_argument, 0, 'c' },
    { "help", no_argument, 0, 'h' },
    { "output", required_argument, 0, 'o' },
    { "lonoff", required_argument, 0, 'O' },
    { "refresh", required_argument, 0, 'r' },
    { "seek", required_argument, 0, 'S' },
    { "server", required_argument, 0, 's' },
    { "speed", required_argument, 0, 'd' },
    { 0, 0, 0, 0 }
};

const char *CONFIG_FILE = TOOL_NAME ".cfg";
const char *OUTPUT_FILE = "watcher.kml";
const char *PROPERTY_FILE = TOOL_NAME ".log.properties";
const char *DEFAULT_HOST = "127.0.0.1";
const unsigned int DEFAULT_REFRESH = 1; // SECONDS

void usage()
{
    const char *SEP = "\t\t";   // separator for argument/description columns

    std::cout << "usage: earthWatcher [ -h ] [ -c FILE ]\n"
        "  -a, --latoff OFF" << SEP << "translate GPS coordinates relative to a given latitude\n"
        "  -A, --altoff OFF" << SEP << "translate GPS coordinates relative to the given altitude\n"
        "  -c, --config FILE" << SEP << "specify a configuration file (default: " << CONFIG_FILE << ")\n"
        "  -d, --speed SPEED" << SEP << "specify the event playback rate (default: 1.0)\n"
        "  -h, --help\t" << SEP << "display this help message\n"
        "  -o, --output FILE" << SEP << "specifies the output KML file (default: " << OUTPUT_FILE << ")\n"
        "  -O, --lonoff OFF" << SEP << "translate GPS coordinates relative to a given longitude\n"
        "  -r, --refresh SECS" << SEP << "write the the output every SECS seconds (default: " << DEFAULT_REFRESH << ")\n"
        "  -s, --server HOST" << SEP << "connect to the watcher server on the given host (default: " << DEFAULT_HOST << ")\n"
        "  -S, --seek POS" << SEP << "start event playback at timestamp POS (default: -1)\n"
        "\tPOS may be specified relative to the first and last timestamps in the Watcher database by prefixing the offset with + or -\n"
        "\tExample: +5000 means 5 seconds after the first event in the database.\n"
        << std::endl;
}

} // end namespace

int main(int argc, char **argv)
{
    TRACE_ENTER();

    const char *output_file = 0;
    Timestamp start_timestamp = -1 ; // default to EOF (live playback)
    unsigned int refresh = DEFAULT_REFRESH;
    float speed = 1.0;
    bool relativeTS = false; // when true, start_timestamp is relative to first or last event in the Watcher DB
    unsigned int args = 0;
    enum {
        argLayerPadding = (1<<0),
        argLonoff = (1<<1),
        argLatoff = (1<<2),
        argAltoff = (1<<3),
        argOutputFile = (1<<4),
        argServerName = (1<<5)
    };
    std::string outputFile(OUTPUT_FILE);
    std::string serverName(DEFAULT_HOST);

    for (int i; (i = getopt_long(argc, argv, "a:A:hc:d:o:O:r:S:", OPTIONS, 0)) != -1; ) {
        switch (i) {
            case 'c':
                break; //handled by initConfig()

            case 'a':
                Latoff = atof(optarg);
                args |= argLatoff;
                break;

            case 'A':
                Altoff = atof(optarg);
                args |= argAltoff;
                break;

            case 'd':
                speed = atof(optarg);
                break;

            case 'o': // output-file
                outputFile = optarg;
                args |= argOutputFile;
                break;

            case 'O':
                Lonoff = atof(optarg);
                args |= argLonoff;
                break;

            case 'r':
                refresh = atoi(optarg);
                break;

            case 'S':
                relativeTS = (optarg[0] == '+' || optarg[0] == '-'); // when +/- is prefix, seek relative to starting/ending event
                start_timestamp = atol(optarg);
                if (start_timestamp == -1)
                    relativeTS = false; // special case for EOF value
                break;

            case 's':
                serverName = optarg;
                args |= argServerName;

            case 'h':
            default:
                usage();
                TRACE_EXIT_RET(EXIT_SUCCESS);
                return EXIT_SUCCESS;
                break;
        }
    }

    libconfig::Config& config = SingletonConfig::instance();
    SingletonConfig::lock();
    std::string configFilename; //filled by initConfig()
    if (! watcher::initConfig(config, argc, argv, configFilename))
        std::cout << "Configuration file not found. Creating new configuration file and using default runtime values." << std::endl;
    SingletonConfig::unlock();

    /* handle log.properties file as a special case */
    std::string logConf(PROPERTY_FILE);
    if (!config.lookupValue("logProperties", logConf)) {
        config.getRoot().add("logProperties", libconfig::Setting::TypeString) = logConf;
    }
    LOAD_LOG_PROPS(logConf);
    LOG_INFO("Logger initialized from file \"" << logConf << "\"");

    std::string service("watcherd");
    struct {
        const char *configName;
        std::string *value;
        unsigned int bit;
    } ConfigString[] = {
        { "server", &serverName, argServerName },
        { "service", &service, 0 },
        { "outputFile", &outputFile, argOutputFile },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigString[i].configName != 0; ++i) {
        if ((args & ConfigString[i].bit) == 0 && !config.lookupValue(ConfigString[i].configName, *ConfigString[i].value)) {
            LOG_INFO("'" << ConfigString[i].configName << "' not found in the configuration file, using default: " << *ConfigString[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigString[i].configName, libconfig::Setting::TypeString) = *ConfigString[i].value;
        }
    }

    LOG_DEBUG("latOff=" << Latoff << " lonOff=" << Lonoff << " altOff=" << Altoff);

    struct {
        const char *configName;
        float* value;
        unsigned int bit;
    } ConfigFloat[] = {
        { "layerPadding", &LayerPadding, argLayerPadding },
        { "lonOff", &Lonoff, argLonoff },
        { "latOff", &Latoff, argLatoff },
        { "altOff", &Altoff, argAltoff },
        { 0, 0, 0 } // terminator
    };

    for (size_t i = 0; ConfigFloat[i].configName != 0; ++i) {
        if ((args & ConfigFloat[i].bit) == 0 && !config.lookupValue(ConfigFloat[i].configName, *ConfigFloat[i].value)) {
            LOG_INFO("'" << ConfigFloat[i].configName << "' not found in the configuration file, using default: " << *ConfigFloat[i].value
                     << " and adding this to the configuration file.");
            config.getRoot().add(ConfigFloat[i].configName, libconfig::Setting::TypeFloat) = *ConfigFloat[i].value;
        }
    }

    // open a message stream of live events for now
    MessageStreamPtr ms(MessageStream::createNewMessageStream(serverName, service, start_timestamp, speed));
    if (!ms) {
        LOG_FATAL("Unable to create new message stream to server \"" << serverName << "\" using service (or port) \"" << service);
        TRACE_EXIT_RET(EXIT_FAILURE);
        return EXIT_FAILURE;
    }

    if (relativeTS) {
        ms->getMessageTimeRange();
    } else {
        LOG_INFO("Starting event playback");
        ms->startStream();
    }

    srandom(time(0));//we use random() to select the icon below
    WatcherGraph graph;

    unsigned int messageNumber = 0;
    MessagePtr mp;
    time_t last_output = 0; // counter to allow for writing the kml file on a fixed time interval
    bool changed = false;
    bool needTimeRange = relativeTS;

    LOG_INFO("Waiting for events ");
    while (ms->getNextMessage(mp)) {
        // std::cout << "Message #" << (++messageNumber) << ": " << *mp << std::endl;

        if (needTimeRange) {
            PlaybackTimeRangeMessagePtr trp(boost::dynamic_pointer_cast<PlaybackTimeRangeMessage>(mp));
            if (trp.get() != 0) {
                LOG_INFO( "first offset=" << trp->min_ << ", last offset=" << trp->max_ );
                needTimeRange = false;

                Timestamp off = start_timestamp + (( start_timestamp >= 0 ) ? trp->min_ : trp->max_ );
                ms->setStreamTimeStart(off);

                LOG_INFO("Starting event playback");
                ms->startStream();

                continue;
            }
        }

        changed |= graph.updateGraph(mp);

        if (changed) {
            time_t now = time(0);
            if (now - last_output >= refresh) {
                graph.doMaintanence(); // expire stale links
                LOG_DEBUG("writing kml file");
                last_output = now;
                write_kml(graph, outputFile);
            }
            changed = false; // reset flag
        }
    }

    // Save any configuration changes made during the run.
    LOG_INFO("Saving last known configuration to " << configFilename);
    SingletonConfig::lock();
    config.writeFile(configFilename.c_str());

    TRACE_EXIT_RET(0);
    return 0;
}
<|endoftext|>


<commit_before>/**
 *
 * Author : Shujia Huang
 * Date   : 2014-08-21
 *
 **/

#include "Region.h"

vector<Region> MergeRegion(vector<Region> &regVect, int delta=1) {
// CAUTION: The 'info' value in each member of regVect will been clean
// after merge!

	vector<Region> newVect;
	map<string, long int> prePos;

	Region reg;
	bool flag(false);
	for (size_t i(0); i < regVect.size(); ++i) {

		if (regVect[i].start > regVect[i].end) {
			cerr << "[ERROR] MergeRegion ERROR! Your region start > end, "
				 << "which does not allow when calling MergeRegion()!\n";
			exit(1);
		}

		if (prePos.count(regVect[i].id)) {

			if (prePos[regVect[i].id] > regVect[i].start) {
				cerr << "[ERROR]Your target hasn't been sorted.\n";
				regVect[i].OutErrReg();
				exit(1);
			}

			if (reg.end + delta >= regVect[i].start) {
				if (reg.end < regVect[i].end) reg.end = regVect[i].end;
			} else {
				newVect.push_back(reg);
				reg = regVect[i];
			}
		} else {

			if (flag) newVect.push_back(reg);
			reg  = regVect[i];
			flag = true;
		}
		prePos[regVect[i].id] = regVect[i].start;
	}
	if (flag) newVect.push_back(reg);

	return newVect;
}

<commit_msg>Add Nocall region into VCF file<commit_after>/**
 *
 * Author : Shujia Huang
 * Date   : 2014-08-21
 *
 **/

#include "Region.h"

vector<Region> MergeRegion(vector<Region> &regVect, int delta=1) {
// CAUTION: The 'info' value in each member of regVect will been clean
// after merge!

	vector<Region> newVect;
	map<string, long int> prePos;

	Region reg;
	bool flag(false);
	for (size_t i(0); i < regVect.size(); ++i) {

		if (regVect[i].start > regVect[i].end) {
			cerr << "[ERROR] MergeRegion ERROR! Your region start > end, "
				 << "which does not allow when calling MergeRegion()!\n";
			exit(1);
		}

		if (prePos.count(regVect[i].id)) {

			if (prePos[regVect[i].id] > regVect[i].start) {
				cerr << "[ERROR]Your target hasn't been sorted.\n";
				regVect[i].OutErrReg();
				exit(1);
			}

			if (reg.end + delta >= regVect[i].start) {
				if (reg.end < regVect[i].end) reg.end = regVect[i].end;
			} else {
				newVect.push_back(reg);
				reg = regVect[i];
			}
		} else {

			if (flag) newVect.push_back(reg);
			reg  = regVect[i];
			flag = true;
		}
		prePos[regVect[i].id] = regVect[i].start;
	}
	if (flag) newVect.push_back(reg);

for (size_t i(0); i < regVect.size(); ++i) {
regVect[i].OutErrReg();
}
cerr << "**** Test Region Merge ****\n";
for (size_t i(0); i < newVect.size(); ++i) {
newVect[i].OutErrReg();
}
exit(1);
	return newVect;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppPresence.h"
#include "QXmppUtils.h"
#include <QtDebug>
#include <QDomElement>
#include <QXmlStreamWriter>
#include "QXmppConstants.h"

QXmppPresence::QXmppPresence(QXmppPresence::Type type,
                             const QXmppPresence::Status& status)
    : QXmppStanza(), m_type(type), m_status(status)
{

}

QXmppPresence::~QXmppPresence()
{

}

QXmppPresence::Type QXmppPresence::type() const
{
    return m_type;
}

void QXmppPresence::setType(QXmppPresence::Type type)
{
    m_type = type;
}

const QXmppPresence::Status& QXmppPresence::status() const
{
    return m_status;
}

QXmppPresence::Status& QXmppPresence::status()
{
    return m_status;
}

void QXmppPresence::setStatus(const QXmppPresence::Status& status)
{
    m_status = status;
}

void QXmppPresence::parse(const QDomElement &element)
{
    QXmppStanza::parse(element);

    setTypeFromStr(element.attribute("type"));
    m_status.parse(element);

    QXmppElementList extensions;
    QDomElement xElement = element.firstChildElement();
    m_vCardUpdateType = VCardUpdateNone;
    while(!xElement.isNull())
    {
        // XEP-0153: vCard-Based Avatars
        if(xElement.namespaceURI() == ns_vcard_update)
        {
            QDomElement photoElement = xElement.firstChildElement("photo");
            if(!photoElement.isNull())
            {
                m_photoHash = QByteArray::fromHex(photoElement.text().toAscii());
                if(m_photoHash.isEmpty())
                    m_vCardUpdateType = PhotoNotAdvertized;
                else
                    m_vCardUpdateType = PhotoAdvertised;
            }
            else
            {
                m_photoHash = QByteArray();
                m_vCardUpdateType = PhotoNotReady;
            }
        }
        // XEP-0115: Entity Capabilities
        else if(xElement.tagName() == "c" && xElement.namespaceURI() == ns_capabilities)
        {
            m_capabilityNode = xElement.attribute("node");
            m_capabilityVer = QByteArray::fromBase64(xElement.attribute("ver").toAscii());
            m_capabilityHash = xElement.attribute("hash");
            m_capabilityExt = xElement.attribute("ext").split(" ", QString::SkipEmptyParts);
        }
        else if (xElement.tagName() == "error")
        {
        }
        else if (xElement.tagName() == "show")
        {
        }
        else if (xElement.tagName() == "status")
        {
        }
        else if (xElement.tagName() == "priority")
        {
        }
        else
        {
            // other extensions
            extensions << QXmppElement(xElement);
        }
        xElement = xElement.nextSiblingElement();
    }
    setExtensions(extensions);
}

void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const
{
    xmlWriter->writeStartElement("presence");
    helperToXmlAddAttribute(xmlWriter,"xml:lang", lang());
    helperToXmlAddAttribute(xmlWriter,"id", id());
    helperToXmlAddAttribute(xmlWriter,"to", to());
    helperToXmlAddAttribute(xmlWriter,"from", from());
    helperToXmlAddAttribute(xmlWriter,"type", getTypeStr());
    m_status.toXml(xmlWriter);

    error().toXml(xmlWriter);

    // XEP-0153: vCard-Based Avatars
    if(m_vCardUpdateType != VCardUpdateNone)
    {
        xmlWriter->writeStartElement("x");
        helperToXmlAddAttribute(xmlWriter, "xmlns", ns_vcard_update);
        switch(m_vCardUpdateType)
        {
        case PhotoNotAdvertized:
            helperToXmlAddTextElement(xmlWriter, "photo", "");
            break;
        case PhotoAdvertised:
            helperToXmlAddTextElement(xmlWriter, "photo", m_photoHash.toHex());
            break;
        case PhotoNotReady:
            break;
        default:
            break;
        }
        xmlWriter->writeEndElement();
    }

    if(!m_capabilityNode.isEmpty() && !m_capabilityVer.isEmpty()
        && !m_capabilityHash.isEmpty())
    {
        xmlWriter->writeStartElement("c");
        helperToXmlAddAttribute(xmlWriter, "xmlns", ns_capabilities);
        helperToXmlAddAttribute(xmlWriter, "hash", m_capabilityHash);
        helperToXmlAddAttribute(xmlWriter, "node", m_capabilityNode);
        helperToXmlAddAttribute(xmlWriter, "ver", m_capabilityVer.toBase64());
        xmlWriter->writeEndElement();
    }

    foreach (const QXmppElement &extension, extensions())
        extension.toXml(xmlWriter);

    xmlWriter->writeEndElement();
}

QString QXmppPresence::getTypeStr() const
{
    QString text;
    switch(m_type)
    {
    case QXmppPresence::Error:
        text = "error";
        break;
    case QXmppPresence::Available:
        // no type-attribute if available
        text = "";
        break;
    case QXmppPresence::Unavailable:
        text = "unavailable";
        break;
    case QXmppPresence::Subscribe:
        text = "subscribe";
        break;
    case QXmppPresence::Subscribed:
        text = "subscribed";
        break;
    case QXmppPresence::Unsubscribe:
        text = "unsubscribe";
        break;
    case QXmppPresence::Unsubscribed:
        text = "unsubscribed";
        break;
    case QXmppPresence::Probe:
        text = "probe";
        break;
    default:
        qWarning("QXmppPresence::getTypeStr() invalid type %d", (int)m_type);
        break;
    }
    return text;
}

void QXmppPresence::setTypeFromStr(const QString& str)
{
    QXmppPresence::Type type;
    if(str == "error")
    {
        type = QXmppPresence::Error;
        setType(type);
        return;
    }
    else if(str == "unavailable")
    {
        type = QXmppPresence::Unavailable;
        setType(type);
        return;
    }
    else if(str == "subscribe")
    {
        type = QXmppPresence::Subscribe;
        setType(type);
        return;
    }
    else if(str == "subscribed")
    {
        type = QXmppPresence::Subscribed;
        setType(type);
        return;
    }
    else if(str == "unsubscribe")
    {
        type = QXmppPresence::Unsubscribe;
        setType(type);
        return;
    }
    else if(str == "unsubscribed")
    {
        type = QXmppPresence::Unsubscribed;
        setType(type);
        return;
    }
    else if(str == "probe")
    {
        type = QXmppPresence::Probe;
        setType(type);
        return;
    }
    else if(str == "")
    {
        type = QXmppPresence::Available;
        setType(type);
        return;
    }
    else
    {
        type = static_cast<QXmppPresence::Type>(-1);
        qWarning("QXmppPresence::setTypeFromStr() invalid input string type: %s",
                 qPrintable(str));
        setType(type);
        return;
    }
}

QXmppPresence::Status::Status(QXmppPresence::Status::Type type,
                             const QString statusText, int priority) :
                                m_type(type),
                                m_statusText(statusText), m_priority(priority)
{
}

QXmppPresence::Status::Type QXmppPresence::Status::type() const
{
    return m_type;
}

void QXmppPresence::Status::setType(QXmppPresence::Status::Type type)
{
    m_type = type;
}

void QXmppPresence::Status::setTypeFromStr(const QString& str)
{
    // there is no keyword for Offline

    QXmppPresence::Status::Type type;
    if(str == "")   // not type-attribute means online
    {
        type = QXmppPresence::Status::Online;
        setType(type);
        return;
    }
    else if(str == "away")
    {
        type = QXmppPresence::Status::Away;
        setType(type);
        return;
    }
    else if(str == "xa")
    {
        type = QXmppPresence::Status::XA;
        setType(type);
        return;
    }
    else if(str == "dnd")
    {
        type = QXmppPresence::Status::DND;
        setType(type);
        return;
    }
    else if(str == "chat")
    {
        type = QXmppPresence::Status::Chat;
        setType(type);
        return;
    }
    else
    {
        type = static_cast<QXmppPresence::Status::Type>(-1);
        qWarning("QXmppPresence::Status::setTypeFromStr() invalid input string type %s",
            qPrintable(str));
        setType(type);
    }
}

QString QXmppPresence::Status::getTypeStr() const
{
    QString text;
    switch(m_type)
    {
    case QXmppPresence::Status::Online:
        // no type-attribute if available
        text = "";
        break;
    case QXmppPresence::Status::Offline:
        text = "";
        break;
    case QXmppPresence::Status::Away:
        text = "away";
        break;
    case QXmppPresence::Status::XA:
        text = "xa";
        break;
    case QXmppPresence::Status::DND:
        text = "dnd";
        break;
    case QXmppPresence::Status::Chat:
        text = "chat";
        break;
    default:
        qWarning("QXmppPresence::Status::getTypeStr() invalid type %d",
                 (int)m_type);
        break;
    }
    return text;
}

QString QXmppPresence::Status::statusText() const
{
    return m_statusText;
}

void QXmppPresence::Status::setStatusText(const QString& str)
{
    m_statusText = str;
}

int QXmppPresence::Status::priority() const
{
    return m_priority;
}

void QXmppPresence::Status::setPriority(int priority)
{
    m_priority = priority;
}

void QXmppPresence::Status::parse(const QDomElement &element)
{
    setTypeFromStr(element.firstChildElement("show").text());
    m_statusText = element.firstChildElement("status").text();
    m_priority = element.firstChildElement("priority").text().toInt();
}

void QXmppPresence::Status::toXml(QXmlStreamWriter *xmlWriter) const
{
    const QString show = getTypeStr();
    if (!show.isEmpty())
        helperToXmlAddTextElement(xmlWriter, "show", getTypeStr());
    if (!m_statusText.isEmpty())
        helperToXmlAddTextElement(xmlWriter, "status", m_statusText);
    if (m_priority != 0)
        helperToXmlAddNumberElement(xmlWriter, "priority", m_priority);
}

QByteArray QXmppPresence::photoHash() const
{
    return m_photoHash;
}

void QXmppPresence::setPhotoHash(const QByteArray& photoHash)
{
    m_photoHash = photoHash;
}

QXmppPresence::VCardUpdateType QXmppPresence::vCardUpdateType()
{
    return m_vCardUpdateType;
}

void QXmppPresence::setVCardUpdateType(VCardUpdateType type)
{
    m_vCardUpdateType = type;
}

/// XEP-0115: Entity Capabilities
QString QXmppPresence::capabilityHash()
{
    return m_capabilityHash;
}

/// XEP-0115: Entity Capabilities
void QXmppPresence::setCapabilityHash(const QString& hash)
{
    m_capabilityHash = hash;
}

/// XEP-0115: Entity Capabilities
QString QXmppPresence::capabilityNode()
{
    return m_capabilityNode;
}

/// XEP-0115: Entity Capabilities
void QXmppPresence::setCapabilityNode(const QString& node)
{
    m_capabilityNode = node;
}

/// XEP-0115: Entity Capabilities
QByteArray QXmppPresence::capabilityVer()
{
    return m_capabilityVer;
}

/// XEP-0115: Entity Capabilities
void QXmppPresence::setCapabilityVer(const QByteArray& ver)
{
    m_capabilityVer = ver;
}

/// Legacy XEP-0115: Entity Capabilities
QStringList QXmppPresence::capabilityExt()
{
    return m_capabilityExt;
}

/// \cond

QXmppPresence::Type QXmppPresence::getType() const
{
    return m_type;
}

const QXmppPresence::Status& QXmppPresence::getStatus() const
{
    return m_status;
}

QXmppPresence::Status& QXmppPresence::getStatus()
{
    return m_status;
}

QXmppPresence::Status::Type QXmppPresence::Status::getType() const
{
    return m_type;
}

QString QXmppPresence::Status::getStatusText() const
{
    return m_statusText;
}

int QXmppPresence::Status::getPriority() const
{
    return m_priority;
}

/// \endcond
<commit_msg>initialise QXmppPresence::m_vCardUpdateType (Closes: #82)<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 */

#include "QXmppPresence.h"
#include "QXmppUtils.h"
#include <QtDebug>
#include <QDomElement>
#include <QXmlStreamWriter>
#include "QXmppConstants.h"

QXmppPresence::QXmppPresence(QXmppPresence::Type type,
                             const QXmppPresence::Status& status)
    : QXmppStanza(),
    m_type(type),
    m_status(status),
    m_vCardUpdateType(VCardUpdateNone)
{

}

QXmppPresence::~QXmppPresence()
{

}

QXmppPresence::Type QXmppPresence::type() const
{
    return m_type;
}

void QXmppPresence::setType(QXmppPresence::Type type)
{
    m_type = type;
}

const QXmppPresence::Status& QXmppPresence::status() const
{
    return m_status;
}

QXmppPresence::Status& QXmppPresence::status()
{
    return m_status;
}

void QXmppPresence::setStatus(const QXmppPresence::Status& status)
{
    m_status = status;
}

void QXmppPresence::parse(const QDomElement &element)
{
    QXmppStanza::parse(element);

    setTypeFromStr(element.attribute("type"));
    m_status.parse(element);

    QXmppElementList extensions;
    QDomElement xElement = element.firstChildElement();
    m_vCardUpdateType = VCardUpdateNone;
    while(!xElement.isNull())
    {
        // XEP-0153: vCard-Based Avatars
        if(xElement.namespaceURI() == ns_vcard_update)
        {
            QDomElement photoElement = xElement.firstChildElement("photo");
            if(!photoElement.isNull())
            {
                m_photoHash = QByteArray::fromHex(photoElement.text().toAscii());
                if(m_photoHash.isEmpty())
                    m_vCardUpdateType = PhotoNotAdvertized;
                else
                    m_vCardUpdateType = PhotoAdvertised;
            }
            else
            {
                m_photoHash = QByteArray();
                m_vCardUpdateType = PhotoNotReady;
            }
        }
        // XEP-0115: Entity Capabilities
        else if(xElement.tagName() == "c" && xElement.namespaceURI() == ns_capabilities)
        {
            m_capabilityNode = xElement.attribute("node");
            m_capabilityVer = QByteArray::fromBase64(xElement.attribute("ver").toAscii());
            m_capabilityHash = xElement.attribute("hash");
            m_capabilityExt = xElement.attribute("ext").split(" ", QString::SkipEmptyParts);
        }
        else if (xElement.tagName() == "error")
        {
        }
        else if (xElement.tagName() == "show")
        {
        }
        else if (xElement.tagName() == "status")
        {
        }
        else if (xElement.tagName() == "priority")
        {
        }
        else
        {
            // other extensions
            extensions << QXmppElement(xElement);
        }
        xElement = xElement.nextSiblingElement();
    }
    setExtensions(extensions);
}

void QXmppPresence::toXml(QXmlStreamWriter *xmlWriter) const
{
    xmlWriter->writeStartElement("presence");
    helperToXmlAddAttribute(xmlWriter,"xml:lang", lang());
    helperToXmlAddAttribute(xmlWriter,"id", id());
    helperToXmlAddAttribute(xmlWriter,"to", to());
    helperToXmlAddAttribute(xmlWriter,"from", from());
    helperToXmlAddAttribute(xmlWriter,"type", getTypeStr());
    m_status.toXml(xmlWriter);

    error().toXml(xmlWriter);

    // XEP-0153: vCard-Based Avatars
    if(m_vCardUpdateType != VCardUpdateNone)
    {
        xmlWriter->writeStartElement("x");
        helperToXmlAddAttribute(xmlWriter, "xmlns", ns_vcard_update);
        switch(m_vCardUpdateType)
        {
        case PhotoNotAdvertized:
            helperToXmlAddTextElement(xmlWriter, "photo", "");
            break;
        case PhotoAdvertised:
            helperToXmlAddTextElement(xmlWriter, "photo", m_photoHash.toHex());
            break;
        case PhotoNotReady:
            break;
        default:
            break;
        }
        xmlWriter->writeEndElement();
    }

    if(!m_capabilityNode.isEmpty() && !m_capabilityVer.isEmpty()
        && !m_capabilityHash.isEmpty())
    {
        xmlWriter->writeStartElement("c");
        helperToXmlAddAttribute(xmlWriter, "xmlns", ns_capabilities);
        helperToXmlAddAttribute(xmlWriter, "hash", m_capabilityHash);
        helperToXmlAddAttribute(xmlWriter, "node", m_capabilityNode);
        helperToXmlAddAttribute(xmlWriter, "ver", m_capabilityVer.toBase64());
        xmlWriter->writeEndElement();
    }

    foreach (const QXmppElement &extension, extensions())
        extension.toXml(xmlWriter);

    xmlWriter->writeEndElement();
}

QString QXmppPresence::getTypeStr() const
{
    QString text;
    switch(m_type)
    {
    case QXmppPresence::Error:
        text = "error";
        break;
    case QXmppPresence::Available:
        // no type-attribute if available
        text = "";
        break;
    case QXmppPresence::Unavailable:
        text = "unavailable";
        break;
    case QXmppPresence::Subscribe:
        text = "subscribe";
        break;
    case QXmppPresence::Subscribed:
        text = "subscribed";
        break;
    case QXmppPresence::Unsubscribe:
        text = "unsubscribe";
        break;
    case QXmppPresence::Unsubscribed:
        text = "unsubscribed";
        break;
    case QXmppPresence::Probe:
        text = "probe";
        break;
    default:
        qWarning("QXmppPresence::getTypeStr() invalid type %d", (int)m_type);
        break;
    }
    return text;
}

void QXmppPresence::setTypeFromStr(const QString& str)
{
    QXmppPresence::Type type;
    if(str == "error")
    {
        type = QXmppPresence::Error;
        setType(type);
        return;
    }
    else if(str == "unavailable")
    {
        type = QXmppPresence::Unavailable;
        setType(type);
        return;
    }
    else if(str == "subscribe")
    {
        type = QXmppPresence::Subscribe;
        setType(type);
        return;
    }
    else if(str == "subscribed")
    {
        type = QXmppPresence::Subscribed;
        setType(type);
        return;
    }
    else if(str == "unsubscribe")
    {
        type = QXmppPresence::Unsubscribe;
        setType(type);
        return;
    }
    else if(str == "unsubscribed")
    {
        type = QXmppPresence::Unsubscribed;
        setType(type);
        return;
    }
    else if(str == "probe")
    {
        type = QXmppPresence::Probe;
        setType(type);
        return;
    }
    else if(str == "")
    {
        type = QXmppPresence::Available;
        setType(type);
        return;
    }
    else
    {
        type = static_cast<QXmppPresence::Type>(-1);
        qWarning("QXmppPresence::setTypeFromStr() invalid input string type: %s",
                 qPrintable(str));
        setType(type);
        return;
    }
}

QXmppPresence::Status::Status(QXmppPresence::Status::Type type,
                             const QString statusText, int priority) :
                                m_type(type),
                                m_statusText(statusText), m_priority(priority)
{
}

QXmppPresence::Status::Type QXmppPresence::Status::type() const
{
    return m_type;
}

void QXmppPresence::Status::setType(QXmppPresence::Status::Type type)
{
    m_type = type;
}

void QXmppPresence::Status::setTypeFromStr(const QString& str)
{
    // there is no keyword for Offline

    QXmppPresence::Status::Type type;
    if(str == "")   // not type-attribute means online
    {
        type = QXmppPresence::Status::Online;
        setType(type);
        return;
    }
    else if(str == "away")
    {
        type = QXmppPresence::Status::Away;
        setType(type);
        return;
    }
    else if(str == "xa")
    {
        type = QXmppPresence::Status::XA;
        setType(type);
        return;
    }
    else if(str == "dnd")
    {
        type = QXmppPresence::Status::DND;
        setType(type);
        return;
    }
    else if(str == "chat")
    {
        type = QXmppPresence::Status::Chat;
        setType(type);
        return;
    }
    else
    {
        type = static_cast<QXmppPresence::Status::Type>(-1);
        qWarning("QXmppPresence::Status::setTypeFromStr() invalid input string type %s",
            qPrintable(str));
        setType(type);
    }
}

QString QXmppPresence::Status::getTypeStr() const
{
    QString text;
    switch(m_type)
    {
    case QXmppPresence::Status::Online:
        // no type-attribute if available
        text = "";
        break;
    case QXmppPresence::Status::Offline:
        text = "";
        break;
    case QXmppPresence::Status::Away:
        text = "away";
        break;
    case QXmppPresence::Status::XA:
        text = "xa";
        break;
    case QXmppPresence::Status::DND:
        text = "dnd";
        break;
    case QXmppPresence::Status::Chat:
        text = "chat";
        break;
    default:
        qWarning("QXmppPresence::Status::getTypeStr() invalid type %d",
                 (int)m_type);
        break;
    }
    return text;
}

QString QXmppPresence::Status::statusText() const
{
    return m_statusText;
}

void QXmppPresence::Status::setStatusText(const QString& str)
{
    m_statusText = str;
}

int QXmppPresence::Status::priority() const
{
    return m_priority;
}

void QXmppPresence::Status::setPriority(int priority)
{
    m_priority = priority;
}

void QXmppPresence::Status::parse(const QDomElement &element)
{
    setTypeFromStr(element.firstChildElement("show").text());
    m_statusText = element.firstChildElement("status").text();
    m_priority = element.firstChildElement("priority").text().toInt();
}

void QXmppPresence::Status::toXml(QXmlStreamWriter *xmlWriter) const
{
    const QString show = getTypeStr();
    if (!show.isEmpty())
        helperToXmlAddTextElement(xmlWriter, "show", getTypeStr());
    if (!m_statusText.isEmpty())
        helperToXmlAddTextElement(xmlWriter, "status", m_statusText);
    if (m_priority != 0)
        helperToXmlAddNumberElement(xmlWriter, "priority", m_priority);
}

QByteArray QXmppPresence::photoHash() const
{
    return m_photoHash;
}

void QXmppPresence::setPhotoHash(const QByteArray& photoHash)
{
    m_photoHash = photoHash;
}

QXmppPresence::VCardUpdateType QXmppPresence::vCardUpdateType()
{
    return m_vCardUpdateType;
}

void QXmppPresence::setVCardUpdateType(VCardUpdateType type)
{
    m_vCardUpdateType = type;
}

/// XEP-0115: Entity Capabilities
QString QXmppPresence::capabilityHash()
{
    return m_capabilityHash;
}

/// XEP-0115: Entity Capabilities
void QXmppPresence::setCapabilityHash(const QString& hash)
{
    m_capabilityHash = hash;
}

/// XEP-0115: Entity Capabilities
QString QXmppPresence::capabilityNode()
{
    return m_capabilityNode;
}

/// XEP-0115: Entity Capabilities
void QXmppPresence::setCapabilityNode(const QString& node)
{
    m_capabilityNode = node;
}

/// XEP-0115: Entity Capabilities
QByteArray QXmppPresence::capabilityVer()
{
    return m_capabilityVer;
}

/// XEP-0115: Entity Capabilities
void QXmppPresence::setCapabilityVer(const QByteArray& ver)
{
    m_capabilityVer = ver;
}

/// Legacy XEP-0115: Entity Capabilities
QStringList QXmppPresence::capabilityExt()
{
    return m_capabilityExt;
}

/// \cond

QXmppPresence::Type QXmppPresence::getType() const
{
    return m_type;
}

const QXmppPresence::Status& QXmppPresence::getStatus() const
{
    return m_status;
}

QXmppPresence::Status& QXmppPresence::getStatus()
{
    return m_status;
}

QXmppPresence::Status::Type QXmppPresence::Status::getType() const
{
    return m_type;
}

QString QXmppPresence::Status::getStatusText() const
{
    return m_statusText;
}

int QXmppPresence::Status::getPriority() const
{
    return m_priority;
}

/// \endcond
<|endoftext|>


<commit_before>#include "QpidPublisher.h"
#include <chrono>

using namespace std::chrono;

// Quote and prefix the project simple topic name.
// * The quotes pass the name to qpid messaging correctly
// * The prefix gets the AMQ broker to use a topic and not a queue
string AmqTopicName(const string name) {
  return "'topic://" + name + "'";
}
string AmqQueueName(const string name) {
  return "'queue://" + name + "'";
}

void QpidPublisher::start(bool asyncMode) {
  printf("QpidPublisher, start, this=%p\n", this);
  // Open connection
  /* Reconnect behaviour can be controlled through the following options:
    * - reconnect: true/false (enables/disables reconnect entirely)
    * - reconnect_timeout: seconds (give up and report failure after specified time)
    * - reconnect_limit: n (give up and report failure after specified number of attempts)
    * - reconnect_interval_min: seconds (initial delay between failed reconnection attempts)
    * - reconnect_interval_max: seconds (maximum delay between failed reconnection attempts)
    * - reconnect_interval: shorthand for setting the same reconnect_interval_min/max
    * - reconnect_urls: list of alternate urls to try when connecting
    *
    * The reconnect_interval is the time that the client waits for
    * after a failed attempt to reconnect before retrying. It starts
    * at the value of the min_retry_interval and is doubled every
    * failure until the value of max_retry_interval is reached.
  */
  // This does not work, reconnect fails to reestablish the flow of messages
  //connection = messaging::Connection(brokerUrl, "{protocol:amqp1.0,reconnect:true,reconnect_interval:30}");
  connection = messaging::Connection(brokerUrl, "{protocol:amqp1.0}");
  connection.open();
  disconnectCount = 0;
  connected = true;

  // Create session
  if(useTransactions) {
    session = connection.createTransactionalSession();
    printf("Created transacted session\n");
  }
  else {
    session = connection.createSession();
    printf("Created non-transacted session\n");
  }

  // Create sender with default topic destination address
  string destName = isUseTopics() ? AmqTopicName(destinationName) : AmqQueueName(destinationName);
  sender = session.createSender(destName);
  printf("Created new sender for: %s\n", destName.c_str());
  senders[destName] = sender;
}

void QpidPublisher::stop() {
  running = false;
  if(sender)
    sender.close();
  if(session)
    session.close();
  if(connection)
    connection.close();
  if(heartbeatMonitorThread) {
    heartbeatMonitorThread->detach();
    heartbeatMonitorThread.reset(nullptr);
  }
  sender = messaging::Sender();
  session = messaging::Session();
  connection = messaging::Connection();
}

void QpidPublisher::queueForPublish(string const &topicName, MqttQOS qos, byte *payload, size_t len) {
  // HACK ALERT: tbd
}

void QpidPublisher::publish(string const &destName, MqttQOS qos, byte *payload, size_t len) {

  // Use default destination unless a new one is specified
  messaging::Sender sndr = sender;
  if (destName.length() > 0) {
    string fullDestName = isUseTopics() ? AmqTopicName(destName) : AmqQueueName(destName);
    sndr = senders[fullDestName];
    if(!sndr) {
      sndr = session.createSender(fullDestName);
      printf("Created new sender for: %s\n", fullDestName.c_str());
      senders[fullDestName] = sndr;
    }
  }

  // Create message
  messaging::Message message((const char *)payload, len);
  if (clientID.length() > 0)
    message.setUserId(clientID);

  // Send message
  sndr.send(message);

  // Close temporary sender
  if (sndr != sender)
    sndr.close();
}

void QpidPublisher::publish(string const &destName, Beacon &beacon) {

  // Use default destination unless a new one is specified
  messaging::Sender sndr = sender;
  if (destName.length() > 0) {
    string fullDestName = isUseTopics() ? AmqTopicName(destName) : AmqQueueName(destName);
    sndr = senders[fullDestName];
    if(!sndr) {
      sndr = session.createSender(fullDestName);
      printf("Created new sender for: %s\n", fullDestName.c_str());
      senders[fullDestName] = sndr;
    }
  }

  doPublishProperties(sndr, beacon, BeconEventType::SCANNER_READ);

  // Close temporary sender
  if (sndr != sender)
    sndr.close();
}

void QpidPublisher::publish(vector<Beacon> events) {
  for(int n = 0; n < events.size(); n ++) {
    Beacon& b = events.at(n);
    publish("", b);
  }
  session.commit();
}

void QpidPublisher::publishStatus(Beacon &beacon) {
  doPublishProperties(sender, beacon, BeconEventType::SCANNER_HEARTBEAT);
}

void QpidPublisher::doPublishProperties(messaging::Sender sndr, Beacon &beacon, BeconEventType messageType) {
  messaging::Message message;
  message.setProperty("uuid", beacon.getUuid());
  message.setProperty("scannerID", beacon.getScannerID());
  message.setProperty("major", beacon.getMajor());
  message.setProperty("minor", beacon.getMinor());
  message.setProperty("manufacturer", beacon.getManufacturer());
  message.setProperty("code", beacon.getCode());
  message.setProperty("power", beacon.getPower());
  message.setProperty("calibratedPower", beacon.getCalibratedPower());
  message.setProperty("rssi", beacon.getRssi());
  message.setProperty("time", beacon.getTime());
  message.setProperty("messageType", messageType);
  message.setProperty("scannerSeqNo", beacon.getScannerSequenceNo());

  if (clientID.length() > 0)
    message.setUserId(clientID);

  // Send message
  sndr.send(message);
}

void QpidPublisher::publishProperties(string const &destName, map<string,string> const &properties) {
  messaging::Sender sndr = sender;
  if (destName.length() > 0) {
    string fullDestName = isUseTopics() ? AmqTopicName(destName) : AmqQueueName(destName);
    sndr = senders[fullDestName];
    if(!sndr) {
      sndr = session.createSender(fullDestName);
      printf("Created new sender for: %s\n", fullDestName.c_str());
      senders[fullDestName] = sndr;
    }
  }

  messaging::Message message;
  for(map<string, string>::const_iterator iter = properties.begin(); iter != properties.end(); iter ++) {
    message.setProperty(iter->first, iter->second);

  }
  message.setProperty("messageType", SCANNER_STATUS);

  if (clientID.length() > 0)
    message.setUserId(clientID);

  // Send message
  sndr.send(message);
}

void QpidPublisher::calculateReconnectTime(int64_t now) {
  setNextReconnectTime(now + reconnectInterval*1000);
  milliseconds ms(now);
  seconds s = duration_cast<seconds>(ms);
  time_t t = s.count();
  fprintf(stderr, "Will attempt reconnect at: %s\n", ctime(&t));
}

void QpidPublisher::monitorHeartbeats(string const &destinationName, heartbeatReceived callback) {
  thread *t = new thread(&QpidPublisher::doMonitorHeartbeats, this, destinationName, callback);
  this->heartbeatMonitorThread.reset(t);
}

void QpidPublisher::doMonitorHeartbeats(string const &destinationName, heartbeatReceived callback) {
  string destName = isUseTopics() ? AmqTopicName(destinationName) : AmqQueueName(destinationName);
  messaging::Receiver receiver = session.createReceiver(destName);
  int missedCount = 0;
  int receivedCount = 0;
  while(running) {
    messaging::Message message;
    try {
      receiver.fetch(message, messaging::Duration::MINUTE);
      receivedCount ++;
      missedCount = 0;
      callback(true, receivedCount, missedCount);
    } catch(messaging::NoMessageAvailable& e) {
      fprintf(stderr, "Failed to receive own heartbeat for 1 minute, %s\n", e.what());
      missedCount ++;
      callback(false, receivedCount, missedCount);
    }
  }
}
<commit_msg>Back to reconnect on by default<commit_after>#include "QpidPublisher.h"
#include <chrono>

using namespace std::chrono;

// Quote and prefix the project simple topic name.
// * The quotes pass the name to qpid messaging correctly
// * The prefix gets the AMQ broker to use a topic and not a queue
string AmqTopicName(const string name) {
  return "'topic://" + name + "'";
}
string AmqQueueName(const string name) {
  return "'queue://" + name + "'";
}

void QpidPublisher::start(bool asyncMode) {
  printf("QpidPublisher, start, this=%p\n", this);
  // Open connection
  /* Reconnect behaviour can be controlled through the following options:
    * - reconnect: true/false (enables/disables reconnect entirely)
    * - reconnect_timeout: seconds (give up and report failure after specified time)
    * - reconnect_limit: n (give up and report failure after specified number of attempts)
    * - reconnect_interval_min: seconds (initial delay between failed reconnection attempts)
    * - reconnect_interval_max: seconds (maximum delay between failed reconnection attempts)
    * - reconnect_interval: shorthand for setting the same reconnect_interval_min/max
    * - reconnect_urls: list of alternate urls to try when connecting
    *
    * The reconnect_interval is the time that the client waits for
    * after a failed attempt to reconnect before retrying. It starts
    * at the value of the min_retry_interval and is doubled every
    * failure until the value of max_retry_interval is reached.
  */
  //connection = messaging::Connection(brokerUrl, "{protocol:amqp1.0}");
  connection = messaging::Connection(brokerUrl, "{protocol:amqp1.0,reconnect:true,reconnect_interval:30}");
  connection.open();
  disconnectCount = 0;
  connected = true;

  // Create session
  if(useTransactions) {
    session = connection.createTransactionalSession();
    printf("Created transacted session\n");
  }
  else {
    session = connection.createSession();
    printf("Created non-transacted session\n");
  }

  // Create sender with default topic destination address
  string destName = isUseTopics() ? AmqTopicName(destinationName) : AmqQueueName(destinationName);
  sender = session.createSender(destName);
  printf("Created new sender for: %s\n", destName.c_str());
  senders[destName] = sender;
}

void QpidPublisher::stop() {
  running = false;
  if(sender)
    sender.close();
  if(session)
    session.close();
  if(connection)
    connection.close();
  if(heartbeatMonitorThread) {
    heartbeatMonitorThread->detach();
    heartbeatMonitorThread.reset(nullptr);
  }
  sender = messaging::Sender();
  session = messaging::Session();
  connection = messaging::Connection();
}

void QpidPublisher::queueForPublish(string const &topicName, MqttQOS qos, byte *payload, size_t len) {
  // HACK ALERT: tbd
}

void QpidPublisher::publish(string const &destName, MqttQOS qos, byte *payload, size_t len) {

  // Use default destination unless a new one is specified
  messaging::Sender sndr = sender;
  if (destName.length() > 0) {
    string fullDestName = isUseTopics() ? AmqTopicName(destName) : AmqQueueName(destName);
    sndr = senders[fullDestName];
    if(!sndr) {
      sndr = session.createSender(fullDestName);
      printf("Created new sender for: %s\n", fullDestName.c_str());
      senders[fullDestName] = sndr;
    }
  }

  // Create message
  messaging::Message message((const char *)payload, len);
  if (clientID.length() > 0)
    message.setUserId(clientID);

  // Send message
  sndr.send(message);

  // Close temporary sender
  if (sndr != sender)
    sndr.close();
}

void QpidPublisher::publish(string const &destName, Beacon &beacon) {

  // Use default destination unless a new one is specified
  messaging::Sender sndr = sender;
  if (destName.length() > 0) {
    string fullDestName = isUseTopics() ? AmqTopicName(destName) : AmqQueueName(destName);
    sndr = senders[fullDestName];
    if(!sndr) {
      sndr = session.createSender(fullDestName);
      printf("Created new sender for: %s\n", fullDestName.c_str());
      senders[fullDestName] = sndr;
    }
  }

  doPublishProperties(sndr, beacon, BeconEventType::SCANNER_READ);

  // Close temporary sender
  if (sndr != sender)
    sndr.close();
}

void QpidPublisher::publish(vector<Beacon> events) {
  for(int n = 0; n < events.size(); n ++) {
    Beacon& b = events.at(n);
    publish("", b);
  }
  session.commit();
}

void QpidPublisher::publishStatus(Beacon &beacon) {
  doPublishProperties(sender, beacon, BeconEventType::SCANNER_HEARTBEAT);
}

void QpidPublisher::doPublishProperties(messaging::Sender sndr, Beacon &beacon, BeconEventType messageType) {
  messaging::Message message;
  message.setProperty("uuid", beacon.getUuid());
  message.setProperty("scannerID", beacon.getScannerID());
  message.setProperty("major", beacon.getMajor());
  message.setProperty("minor", beacon.getMinor());
  message.setProperty("manufacturer", beacon.getManufacturer());
  message.setProperty("code", beacon.getCode());
  message.setProperty("power", beacon.getPower());
  message.setProperty("calibratedPower", beacon.getCalibratedPower());
  message.setProperty("rssi", beacon.getRssi());
  message.setProperty("time", beacon.getTime());
  message.setProperty("messageType", messageType);
  message.setProperty("scannerSeqNo", beacon.getScannerSequenceNo());

  if (clientID.length() > 0)
    message.setUserId(clientID);

  // Send message
  sndr.send(message);
}

void QpidPublisher::publishProperties(string const &destName, map<string,string> const &properties) {
  messaging::Sender sndr = sender;
  if (destName.length() > 0) {
    string fullDestName = isUseTopics() ? AmqTopicName(destName) : AmqQueueName(destName);
    sndr = senders[fullDestName];
    if(!sndr) {
      sndr = session.createSender(fullDestName);
      printf("Created new sender for: %s\n", fullDestName.c_str());
      senders[fullDestName] = sndr;
    }
  }

  messaging::Message message;
  for(map<string, string>::const_iterator iter = properties.begin(); iter != properties.end(); iter ++) {
    message.setProperty(iter->first, iter->second);

  }
  message.setProperty("messageType", SCANNER_STATUS);

  if (clientID.length() > 0)
    message.setUserId(clientID);

  // Send message
  sndr.send(message);
}

void QpidPublisher::calculateReconnectTime(int64_t now) {
  setNextReconnectTime(now + reconnectInterval*1000);
  milliseconds ms(now);
  seconds s = duration_cast<seconds>(ms);
  time_t t = s.count();
  fprintf(stderr, "Will attempt reconnect at: %s\n", ctime(&t));
}

void QpidPublisher::monitorHeartbeats(string const &destinationName, heartbeatReceived callback) {
  thread *t = new thread(&QpidPublisher::doMonitorHeartbeats, this, destinationName, callback);
  this->heartbeatMonitorThread.reset(t);
}

void QpidPublisher::doMonitorHeartbeats(string const &destinationName, heartbeatReceived callback) {
  string destName = isUseTopics() ? AmqTopicName(destinationName) : AmqQueueName(destinationName);
  messaging::Receiver receiver = session.createReceiver(destName);
  int missedCount = 0;
  int receivedCount = 0;
  while(running) {
    messaging::Message message;
    try {
      receiver.fetch(message, messaging::Duration::MINUTE);
      receivedCount ++;
      missedCount = 0;
      callback(true, receivedCount, missedCount);
    } catch(messaging::NoMessageAvailable& e) {
      fprintf(stderr, "Failed to receive own heartbeat for 1 minute, %s\n", e.what());
      missedCount ++;
      callback(false, receivedCount, missedCount);
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "base/fscapi.h"

#if FUN_TRANSPORT_AGENT == FUN_MAC_TRANSPORT_AGENT

#include <Foundation/Foundation.h>
#include <CoreFoundation/CoreFoundation.h>
//#if defined(FUN_IPHONE)
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCNetworkReachability.h>
//#if TARGET_IPHONE_SIMULATOR
//#include <CoreServices/CoreServices.h>
//#else
#include <CFNetwork/CFNetwork.h>
//#endif
//#else
//#include <CoreServices/CoreServices.h>
//#endif

#include "http/MacTransportAgent.h"
#include "http/constants.h"

#include "base/util/utils.h"
#include "base/util/StringBuffer.h"

USE_NAMESPACE

MacTransportAgent::MacTransportAgent() : TransportAgent() {}

MacTransportAgent::~MacTransportAgent() {}

/*
 * Constructor.
 * In this implementation newProxy is ignored, since proxy configuration
 * is taken from the WinInet subsystem.
 *
 * @param url the url where messages will be sent with sendMessage()
 * @param proxy proxy information or NULL if no proxy should be used
 */
MacTransportAgent::MacTransportAgent(URL& newURL, Proxy& newProxy, unsigned int maxResponseTimeout)
: TransportAgent(newURL, newProxy, maxResponseTimeout)
{}

/*
 * Sends the given SyncML message to the server specified
 * by the instal property 'url'. Returns the response status code or -1
 * if it was not possible initialize the connection.
 *
 * Use getResponse() to get the server response.
 */
char* MacTransportAgent::sendMessage(const char* msg){
    LOG.debug("MacTransportAgent::sendMessage begin");
    if(!msg) {
        LOG.error("MacTransportAgent::sendMessage error: NULL message.");
        setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: NULL message.");
        return NULL;
    }

    bool gotflags = true;
    bool isReachable = true;
    bool noConnectionRequired = true;

    StringBuffer result;
    CFIndex bytesRead = 1;
    int statusCode = -1;

#if defined(FUN_IPHONE)
    SCNetworkReachabilityFlags        flags;
    SCNetworkReachabilityRef scnReachRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, url.host);

    gotflags = SCNetworkReachabilityGetFlags(scnReachRef, &flags);
    isReachable = flags & kSCNetworkReachabilityFlagsReachable;
    noConnectionRequired = !(flags & kSCNetworkReachabilityFlagsConnectionRequired);
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN)) {
        noConnectionRequired = true;
    }
    CFRelease(scnReachRef);
#endif

    if ( gotflags && isReachable && noConnectionRequired ){
        char* ret=0;
        // size_t size = strlen(msg);
        LOG.debug("Requesting resource %s at %s:%d", url.resource, url.host, url.port);

        LOG.debug("Sending HTTP Request: %s", msg);

        // Construct some headers
        CFStringRef headerFieldName = CFSTR("Content-Type");
        CFStringRef headerFieldValue = CFSTR("application/vnd.syncml+xml");

        // Construct URL
        CFStringRef CFurl =  CFStringCreateWithCString(NULL, url.fullURL, kCFStringEncodingUTF8);
        CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, CFurl, NULL);

        CFStringRef requestMethod = CFSTR("POST");

        CFHTTPMessageRef httpRequest =
        CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1);
        CFStringRef useragent = CFStringCreateWithCString(NULL, getUserAgent(), kCFStringEncodingUTF8);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, CFSTR("user-agent"),  useragent);
        if(!httpRequest){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");

            goto finally;
        }

        CFDataRef bodyData;
        bodyData = CFDataCreate(kCFAllocatorDefault, (const UInt8*)msg, strlen(msg));
        if (!bodyData){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            goto finally;
        }
        CFHTTPMessageSetBody(httpRequest, bodyData);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, headerFieldName, headerFieldValue);

        CFReadStreamRef responseStream;
        responseStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, httpRequest);

        //bool setProperty;
        //if we are trying to sync on a https server we have to have a trusted certificate.
        //no self signed certificates are accepted
        /*if(strcmp(url.protocol, "https")==0){
            NSDictionary *sslProperties;
            sslProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                               (NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamSSLLevel,
                                               kCFBooleanFalse, kCFStreamSSLAllowsAnyRoot,
                                               kCFBooleanTrue, kCFStreamSSLValidatesCertificateChain,
                                               kCFNull, kCFStreamSSLPeerName,
                                               nil];

            setProperty = CFReadStreamSetProperty( responseStream,
                                                  kCFStreamPropertySSLSettings,
                                                  sslProperties );
            [sslProperties release];
        }*/

        if (!CFReadStreamOpen(responseStream)) {//Sends request
            LOG.error("Failed to send HTTP request...");
        }

#define READ_SIZE 1000

        UInt8   buffer[READ_SIZE];
        while ( (bytesRead = CFReadStreamRead(responseStream, buffer, READ_SIZE-1)) > 0)
        {
            //   Convert what was read to a C-string
            buffer[bytesRead] = 0;
            //   Append it to the reply string
            result.append((const char*)buffer);
        }

        CFHTTPMessageRef reply;
        reply = (CFHTTPMessageRef) CFReadStreamCopyProperty( responseStream, kCFStreamPropertyHTTPResponseHeader);

        // Pull the status code from the headers
        if (reply) {
            statusCode = CFHTTPMessageGetResponseStatusCode(reply);
            CFRelease(reply);
        }

        LOG.debug("Status Code: %d", statusCode);
        LOG.debug("Result: %s", result.c_str());

        switch (statusCode) {
            case 0: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case 200: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case -1: {                    // no connection (TODO: implement retry)
                setErrorF(ERR_SERVER_ERROR, "Network error in server receiving data. ");
                LOG.error("%s", getLastErrorMsg());

                break;
            }
            case 400: {                    // 400 bad request error. TODO: retry to send the message
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());

                break;
            }
            case 500: {     // 500 -> out code 2052
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 404: {         // 404 -> out code 2060
                setErrorF(ERR_HTTP_NOT_FOUND, "HTTP request error: resource not found (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 408: {   // 408 -> out code 2061
                setErrorF(ERR_HTTP_REQUEST_TIMEOUT, "HTTP request error: server timed out waiting for request (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }

            default: {
                setErrorF(statusCode, "HTTP request error: status received = %d", statusCode);
                LOG.error("%s", getLastErrorMsg());
            }
        }

    finally:
        CFRelease(headerFieldName);
        CFRelease(headerFieldValue);
        CFRelease(CFurl);
        CFRelease(myURL);
        CFRelease(httpRequest);
        CFRelease(bodyData);
        CFRelease(responseStream);
        CFRelease(requestMethod);
        CFRelease(useragent);

        LOG.debug("MacTransportAgent::sendMessage end");
        return ret;
    }else{
        setErrorF(ERR_CONNECT, "Network error: the attempt to connect to the server failed -> exit");
        LOG.debug("%s", getLastErrorMsg());
        LOG.debug("MacTransportAgent::sendMessage end");
        return NULL;
    }
}

#endif

<commit_msg>corrected MacTransportAgent to avoid performance issues<commit_after>/*
 * Funambol is a mobile platform developed by Funambol, Inc.
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 *
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "base/fscapi.h"

#if FUN_TRANSPORT_AGENT == FUN_MAC_TRANSPORT_AGENT

#include <Foundation/Foundation.h>
#include <CoreFoundation/CoreFoundation.h>
#if defined(FUN_IPHONE)
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCNetworkReachability.h>
//#if TARGET_IPHONE_SIMULATOR
//#include <CoreServices/CoreServices.h>
//#else
#include <CFNetwork/CFNetwork.h>
#else
#include <CoreServices/CoreServices.h>
#endif

#include "http/MacTransportAgent.h"
#include "http/constants.h"

#include "base/util/utils.h"
#include "base/util/StringBuffer.h"

USE_NAMESPACE

MacTransportAgent::MacTransportAgent() : TransportAgent() {}

MacTransportAgent::~MacTransportAgent() {}

/*
 * Constructor.
 * In this implementation newProxy is ignored, since proxy configuration
 * is taken from the WinInet subsystem.
 *
 * @param url the url where messages will be sent with sendMessage()
 * @param proxy proxy information or NULL if no proxy should be used
 */
MacTransportAgent::MacTransportAgent(URL& newURL, Proxy& newProxy, unsigned int maxResponseTimeout)
: TransportAgent(newURL, newProxy, maxResponseTimeout)
{}

/*
 * Sends the given SyncML message to the server specified
 * by the instal property 'url'. Returns the response status code or -1
 * if it was not possible initialize the connection.
 *
 * Use getResponse() to get the server response.
 */
char* MacTransportAgent::sendMessage(const char* msg){
    LOG.debug("MacTransportAgent::sendMessage begin");
    if(!msg) {
        LOG.error("MacTransportAgent::sendMessage error: NULL message.");
        setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: NULL message.");
        return NULL;
    }

    bool gotflags = true;
    bool isReachable = true;
    bool noConnectionRequired = true;

    StringBuffer result;
    CFIndex bytesRead = 1;
    int statusCode = -1;

#if defined(FUN_IPHONE)
    SCNetworkReachabilityFlags        flags;
    SCNetworkReachabilityRef scnReachRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, url.host);

    gotflags = SCNetworkReachabilityGetFlags(scnReachRef, &flags);
    isReachable = flags & kSCNetworkReachabilityFlagsReachable;
    noConnectionRequired = !(flags & kSCNetworkReachabilityFlagsConnectionRequired);
    if ((flags & kSCNetworkReachabilityFlagsIsWWAN)) {
        noConnectionRequired = true;
    }
    CFRelease(scnReachRef);
#endif

    if ( gotflags && isReachable && noConnectionRequired ){
        char* ret=0;
        // size_t size = strlen(msg);
        LOG.debug("Requesting resource %s at %s:%d", url.resource, url.host, url.port);

        LOG.debug("Sending HTTP Request: %s", msg);

        // Construct some headers
        CFStringRef headerFieldName = CFSTR("Content-Type");
        CFStringRef headerFieldValue = CFSTR("application/vnd.syncml+xml");

        // Construct URL
        CFStringRef CFurl =  CFStringCreateWithCString(NULL, url.fullURL, kCFStringEncodingUTF8);
        CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, CFurl, NULL);

        CFStringRef requestMethod = CFSTR("POST");

        CFHTTPMessageRef httpRequest =
        CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL, kCFHTTPVersion1_1);
        CFStringRef useragent = CFStringCreateWithCString(NULL, getUserAgent(), kCFStringEncodingUTF8);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, CFSTR("user-agent"),  useragent);
        if(!httpRequest){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");

            goto finally;
        }

        //CFDataRef bodyData;
        CFDataRef bodyData = CFDataCreate(kCFAllocatorDefault, (const UInt8*)msg, strlen(msg));
        if (!bodyData){
            LOG.error("MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            setError(ERR_NETWORK_INIT, "MacTransportAgent::sendMessage error: CFHTTPMessageCreateRequest Error.");
            goto finally;
        }
        CFHTTPMessageSetBody(httpRequest, bodyData);
        CFHTTPMessageSetHeaderFieldValue(httpRequest, headerFieldName, headerFieldValue);

        //CFReadStreamRef responseStream;
        CFReadStreamRef responseStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, httpRequest);

        //bool setProperty;
        //if we are trying to sync on a https server we have to have a trusted certificate.
        //no self signed certificates are accepted
        /*if(strcmp(url.protocol, "https")==0){
            NSDictionary *sslProperties;
            sslProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                               (NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL, kCFStreamSSLLevel,
                                               kCFBooleanFalse, kCFStreamSSLAllowsAnyRoot,
                                               kCFBooleanTrue, kCFStreamSSLValidatesCertificateChain,
                                               kCFNull, kCFStreamSSLPeerName,
                                               nil];

            setProperty = CFReadStreamSetProperty( responseStream,
                                                  kCFStreamPropertySSLSettings,
                                                  sslProperties );
            [sslProperties release];
        }*/

        if (!CFReadStreamOpen(responseStream)) {//Sends request
            LOG.error("Failed to send HTTP request...");
        }

#define READ_SIZE 1000

        UInt8   buffer[READ_SIZE];
        while ( (bytesRead = CFReadStreamRead(responseStream, buffer, READ_SIZE-1)) > 0)
        {
            //   Convert what was read to a C-string
            buffer[bytesRead] = 0;
            //   Append it to the reply string
            result.append((const char*)buffer);
        }

        //CFHTTPMessageRef reply;
        CFHTTPMessageRef reply = (CFHTTPMessageRef) CFReadStreamCopyProperty( responseStream, kCFStreamPropertyHTTPResponseHeader);

        // Pull the status code from the headers
        if (reply) {
            statusCode = CFHTTPMessageGetResponseStatusCode(reply);
            CFRelease(reply);
        }

        LOG.debug("Status Code: %d", statusCode);
        LOG.debug("Result: %s", result.c_str());

        switch (statusCode) {
            case 0: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case 200: {
                LOG.debug("Http request successful.");

                // No errors, copy the response
                // TODO: avoid byte copy
                ret = stringdup(result.c_str());

                break;
            }
            case -1: {                    // no connection (TODO: implement retry)
                setErrorF(ERR_SERVER_ERROR, "Network error in server receiving data. ");
                LOG.error("%s", getLastErrorMsg());

                break;
            }
            case 400: {                    // 400 bad request error. TODO: retry to send the message
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());

                break;
            }
            case 500: {     // 500 -> out code 2052
                setErrorF(ERR_SERVER_ERROR, "HTTP server error: %d. Server failure.", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 404: {         // 404 -> out code 2060
                setErrorF(ERR_HTTP_NOT_FOUND, "HTTP request error: resource not found (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }
            case 408: {   // 408 -> out code 2061
                setErrorF(ERR_HTTP_REQUEST_TIMEOUT, "HTTP request error: server timed out waiting for request (status %d)", statusCode);
                LOG.debug("%s", getLastErrorMsg());
                break;
            }

            default: {
                setErrorF(statusCode, "HTTP request error: status received = %d", statusCode);
                LOG.error("%s", getLastErrorMsg());
            }
        }

    finally:
        CFRelease(headerFieldName);
        CFRelease(headerFieldValue);
        CFRelease(CFurl);
        CFRelease(myURL);
        CFRelease(httpRequest);
        CFRelease(bodyData);
        CFRelease(responseStream);
        CFRelease(requestMethod);
        CFRelease(useragent);

        LOG.debug("MacTransportAgent::sendMessage end");
        return ret;
    }else{
        setErrorF(ERR_CONNECT, "Network error: the attempt to connect to the server failed -> exit");
        LOG.debug("%s", getLastErrorMsg());
        LOG.debug("MacTransportAgent::sendMessage end");
        return NULL;
    }
}

#endif

<|endoftext|>