From c5bb67eab6f97ae0f5f7e673ff0ba9b1111191f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Sat, 9 Oct 2010 11:52:51 +0200 Subject: Added EchoBot walkthrough example. diff --git a/BuildTools/Copyrighter.py b/BuildTools/Copyrighter.py index 7f4d9f9..b83c3d6 100755 --- a/BuildTools/Copyrighter.py +++ b/BuildTools/Copyrighter.py @@ -136,7 +136,7 @@ elif sys.argv[1] == "check-all-copyrights" : for (path, dirs, files) in os.walk(".") : if "3rdParty" in path or ".sconf" in path or "Swift.app" in path : continue - for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file] : + for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file and not "Swiften.h" in file ] : ok &= check_copyright(filename) if not ok : sys.exit(-1) diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/.gitignore b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/.gitignore new file mode 100644 index 0000000..28275ad --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/.gitignore @@ -0,0 +1,2 @@ +EchoBot? +*.cpp.xml diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp new file mode 100644 index 0000000..584ec9d --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Swiften.h" + +using namespace Swift; + +int main(int, char*) { + SimpleEventLoop eventLoop; + + Client client(JID("echobot@wonderland.lit"), "mypass"); + client.connect(); + + eventLoop.run(); + + return 0; +} diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp new file mode 100644 index 0000000..a03c3db --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include +#include + +#include "Swiften/Swiften.h" + +using namespace Swift; +using namespace boost; + +Client* client; + +void handleConnected() { + std::cout << "Connected" << std::endl; +} + +void handleMessageReceived(Message::ref message) { + // Echo back the incoming message + message->setTo(message->getFrom()); + message->setFrom(JID()); + client->sendMessage(message); +} + +int main(int, char*) { + SimpleEventLoop eventLoop; + + client = new Client(JID("echobot@wonderland.lit"), "mypass"); + client->onConnected.connect(&handleConnected); + client->onMessageReceived.connect(bind(&handleMessageReceived, _1)); + client->connect(); + + eventLoop.run(); + + delete client; + return 0; +} diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp new file mode 100644 index 0000000..a9c611f --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include +#include + +#include "Swiften/Swiften.h" + +using namespace Swift; +using namespace boost; + +class EchoBot { + public: + EchoBot() { + client = new Client(JID("echobot@wonderland.lit"), "mypass"); + client->onConnected.connect(bind(&EchoBot::handleConnected, this)); + client->onMessageReceived.connect( + bind(&EchoBot::handleMessageReceived, this, _1)); + tracer = new ClientXMLTracer(client); + client->connect(); + } + + ~EchoBot() { + delete tracer; + delete client; + } + + private: + void handleConnected() { + std::cout << "Connected" << std::endl; + } + + void handleMessageReceived(Message::ref message) { + // Echo back the incoming message + message->setTo(message->getFrom()); + message->setFrom(JID()); + client->sendMessage(message); + } + + private: + Client* client; + ClientXMLTracer* tracer; +}; + +int main(int, char*) { + SimpleEventLoop eventLoop; + EchoBot bot; + eventLoop.run(); + return 0; +} diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp new file mode 100644 index 0000000..b01fecd --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +//... +#include +#include + +#include "Swiften/Swiften.h" + +using namespace Swift; +using namespace boost; +//... +class EchoBot { + public: + EchoBot() { + //... + client = new Client(JID("echobot@wonderland.lit"), "mypass"); + client->onConnected.connect(bind(&EchoBot::handleConnected, this)); + client->onMessageReceived.connect( + bind(&EchoBot::handleMessageReceived, this, _1)); + //... + client->onPresenceReceived.connect( + bind(&EchoBot::handlePresenceReceived, this, _1)); + //... + tracer = new ClientXMLTracer(client); + client->connect(); + //... + } + + //... + ~EchoBot() { + delete tracer; + delete client; + } + + private: + //... + void handlePresenceReceived(Presence::ref presence) { + // Automatically approve subscription requests + if (presence->getType() == Presence::Subscribe) { + Presence::ref response = Presence::create(); + response->setTo(presence->getFrom()); + response->setType(Presence::Subscribed); + client->sendPresence(response); + } + } + + void handleConnected() { + // Request the roster + GetRosterRequest::ref rosterRequest = + GetRosterRequest::create(client->getIQRouter()); + rosterRequest->onResponse.connect( + bind(&EchoBot::handleRosterReceived, this, _2)); + rosterRequest->send(); + } + + void handleRosterReceived(const optional& error) { + if (error) { + std::cerr << "Error receiving roster. Continuing anyway."; + } + // Send initial available presence + client->sendPresence(Presence::create("Send me a message")); + } + //... + + void handleMessageReceived(Message::ref message) { + // Echo back the incoming message + message->setTo(message->getFrom()); + message->setFrom(JID()); + client->sendMessage(message); + } + + private: + Client* client; + ClientXMLTracer* tracer; + //... +}; +//... + +int main(int, char*) { + SimpleEventLoop eventLoop; + EchoBot bot; + eventLoop.run(); + return 0; +} +//... diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp new file mode 100644 index 0000000..72d0eb1 --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +//... +#include +#include + +#include "Swiften/Swiften.h" + +using namespace Swift; +using namespace boost; +//... +class EchoBot { + public: + EchoBot() { + //... + client = new Client(JID("echobot@wonderland.lit"), "mypass"); + client->onConnected.connect(bind(&EchoBot::handleConnected, this)); + client->onMessageReceived.connect( + bind(&EchoBot::handleMessageReceived, this, _1)); + client->onPresenceReceived.connect( + bind(&EchoBot::handlePresenceReceived, this, _1)); + tracer = new ClientXMLTracer(client); + //... + softwareVersionResponder = new SoftwareVersionResponder( + "EchoBot", "1.0", client->getIQRouter()); + //... + client->connect(); + //... + } + + ~EchoBot() { + delete softwareVersionResponder; + //... + delete tracer; + delete client; + //... + } + //... + + private: + void handlePresenceReceived(Presence::ref presence) { + // Automatically approve subscription requests + if (presence->getType() == Presence::Subscribe) { + Presence::ref response = Presence::create(); + response->setTo(presence->getFrom()); + response->setType(Presence::Subscribed); + client->sendPresence(response); + } + } + + void handleConnected() { + // Request the roster + GetRosterRequest::ref rosterRequest = + GetRosterRequest::create(client->getIQRouter()); + rosterRequest->onResponse.connect( + bind(&EchoBot::handleRosterReceived, this, _2)); + rosterRequest->send(); + } + + void handleRosterReceived(const optional& error) { + if (error) { + std::cerr << "Error receiving roster. Continuing anyway."; + } + // Send initial available presence + client->sendPresence(Presence::create("Send me a message")); + } + + void handleMessageReceived(Message::ref message) { + // Echo back the incoming message + message->setTo(message->getFrom()); + message->setFrom(JID()); + client->sendMessage(message); + } + + //... + private: + //... + Client* client; + ClientXMLTracer* tracer; + //... + SoftwareVersionResponder* softwareVersionResponder; +}; +//... + +int main(int, char*) { + SimpleEventLoop eventLoop; + EchoBot bot; + eventLoop.run(); + return 0; +} +//... diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript new file mode 100644 index 0000000..ceead6b --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript @@ -0,0 +1,15 @@ +Import("env") + +example_env = env.Clone() +example_env.MergeFlags(example_env["SWIFTEN_FLAGS"]) +example_env.MergeFlags(example_env["LIBIDN_FLAGS"]) +example_env.MergeFlags(example_env["BOOST_FLAGS"]) +example_env.MergeFlags(example_env.get("SQLITE_FLAGS", {})) +example_env.MergeFlags(example_env["ZLIB_FLAGS"]) +example_env.MergeFlags(example_env["OPENSSL_FLAGS"]) +example_env.MergeFlags(example_env.get("LIBXML_FLAGS", "")) +example_env.MergeFlags(example_env.get("EXPAT_FLAGS", "")) +example_env.MergeFlags(example_env["PLATFORM_FLAGS"]) + +for i in range(1,6) : + example_env.Program("EchoBot" + str(i), ["EchoBot" + str(i) + ".cpp"]) diff --git a/Documentation/SwiftenDevelopersGuide/Examples/SConscript b/Documentation/SwiftenDevelopersGuide/Examples/SConscript new file mode 100644 index 0000000..1284b34 --- /dev/null +++ b/Documentation/SwiftenDevelopersGuide/Examples/SConscript @@ -0,0 +1 @@ +SConscript(dirs = ["EchoBot"]) diff --git a/Documentation/SwiftenDevelopersGuide/SConscript b/Documentation/SwiftenDevelopersGuide/SConscript index 145663f..fb08a8f 100644 --- a/Documentation/SwiftenDevelopersGuide/SConscript +++ b/Documentation/SwiftenDevelopersGuide/SConscript @@ -2,4 +2,89 @@ Import("env") env.Tool("DocBook", toolpath = ["#/BuildTools/DocBook/SCons"]) +################################################################################ +# Code generation helper +################################################################################ + +import sys, re, os.path + +def generateDocBookCode(env, target, source) : + # Strips empty lines from the beginning & end of a program + def stripEmptyLines(program) : + programLines = program.split('\n') + newProgramLines = [] + inProgram = False + for line in programLines : + if not re.match("^\s*$", line) or inProgram : + inProgram = True + newProgramLines.append(line) + return '\n'.join(newProgramLines).rstrip() + + def createCallouts(program, calloutPrefix) : + newProgramLines = [] + calloutLines = [] + nextID = 0 + for line in program.split("\n") : + # FIXME: Takes the largest match + m = re.match(".*\/* \(\*\) (.*) \*/.*", line) + if m : + cobID = "cob-" + calloutPrefix + "-" + str(nextID) + coID = "co-" + calloutPrefix + "-" + str(nextID) + nextID += 1 + line = re.sub("/\*.*\*/", "]]>%(text)s" % {"cobID": cobID, "coID": coID, "text": m.group(1)}) + newProgramLines.append(line) + callouts = "" + "\n".join(calloutLines) + "" if len(calloutLines) > 0 else "" + return ("\n".join(newProgramLines), callouts) + + # Parse program + filename = source[0].abspath + filenameBase = os.path.basename(filename).replace(".cpp", "") + inputfile = open(filename) + program = "" + programs = {} + programName = "" + inEllipsis = False + for line in inputfile.readlines() : + if inEllipsis : + if "//..." in line : + inEllipsis = False + else : + if line.startswith("/*") or line.startswith(" *") : + continue + if "//..." in line : + inEllipsis = True + line = line.replace("//...", "]]>…" + callouts + "" + + # Generate code + output = open(target[0].abspath, 'w') + output.write(document) + output.close() + +################################################################################ + env.DocBook("Swiften Developers Guide.xml") + +for i in range(1, 6) : + source = "Examples/EchoBot/EchoBot" + str(i) + ".cpp" + env.Command(source + ".xml", source, Action(generateDocBookCode, cmdstr = "$GENCOMSTR")) + +SConscript(dirs = ["Examples"]) diff --git a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml index e0a63ae..1df3781 100644 --- a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml +++ b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml @@ -6,44 +6,322 @@ Introduction +
+ Prerequisites + + We assume that the reader is familiar with the basics of the + XMPP protocol. For an overview of the XMPP protocol and its + workings, see + XMPP: The Definitive Guide + + +
- - This is an introduction - - - - Section - +
+ Boost - This is a section + Swiften makes heavy use of Boost (http://boost.org) libraries, including Signal, + Bind, Optional, and + Smart Pointers. We + introduce the basic usage of these libraries in our API throughout + this manual. For detailed documentation, we refer to the Boost + website. - +
Tutorial: Writing an Echo Bot - In this chapter, we build a simple echo bot, illustrating how - to use and extend Swiften for your own purposes. + In this chapter, we guide you through the Swiften API by building an + example XMPP application: an EchoBot. This example program, taken from + XMPP: The Definitive Guide + , connects to + an XMPP server, logs in, and responds to all incoming messages with + the exact same message. We build up our application using Swiften's + basic building blocks for XMPP development, to help get a good + understanding of how Swiften fundamental classes work and can be + extended. In the last stage of this example, we + introduce some of Swiften's convenience classes for standard + XMPP tasks such as roster management. - Setting up the build environment + Connecting to a server: Clients & event loops + + As a first step, we create an application that connects to a server. + The code can be seen in . + + + Connecting to a server + + + + The first thing this program does is construct an + Event Loop. An event loop is a seemingly infinite + loop that waits for external events (e.g. incoming network packets, + timers being activated, input happening) to happen; when such an event + comes in, it notifies interested parties of this event, and then + continues listening for the next event. Since many application + frameworks (such as Qt, GLib, Cocoa) use their own event loop, + Swiften comes prepackaged with classes that integrate with these + event loops. These classes can be found in + Swiften/EventLoop. + In this example, however, we don't use such a framework, + so we use Swiften's own SimpleEventLoop. This + class is used by simply instantiating it at the beginning of the + application, and calling run() after everything + is set up, which will go into an infinite loop. Apart from constructing + and (if necessary) starting the event loop, you will probably have + no other contact with it in the rest of the application. + + + + Swiften's central class for implementing XMPP applications is + Client. This class handles all the interaction + with the XMPP network. After constructing it with the JID and + password with which we want to connect, we call + connect() to instruct the client to connect to + the XMPP server with the given credentials. Note that this call returns + immediately; it is only when starting the event loop that network + the actual connection process will start. + + + + + Building EchoBot + TODO: Explain linking against the static library. + + + + Reacting to events: Signals, Slots & Bind + + Up to this point, our client doesn't do anything useful. In this + section, we make the client react to XMPP events. The code can + be seen in . + + + Reacting to events: Notify whenever the client is connected to the network, and echo back incoming messages + + + + + A first thing we want to do is print out a message when the client + is connected to the server. Swiften uses the + signal/slot paradigm for notifying interested + parties of events. A signal is an object + representing a type of event. For example, Client + has an onConnected signal for notifying whenever + the client is connected to the network. If you are interested in + a particular signal, you connect a slot to the + signal. A slot represents a callback that will be called whenever a + signal is emitted. Since we want to print out a message whenever + we're connected to the network, we connect to the client's signal, + and tell it to call handleConnected (which prints + out a message): + client->onConnected.connect(&handleConnected) + + + + Another event we're interested in is whenever a message comes in. + For this purpose, Client provides a signal called + onMessageReceived. The major difference with the + previous onConnected signal is that this signal + also can provide extra information to the callback: the actual + message received. A signal can provide this extra information through + one or more arguments, which will be passed to the slot's parameters. + To be able to handle parameters to slots, there needs to be a more + general representation of callbacks than just function pointers. This + is where Boost's bind comes in: bind + provides a way to construct functors (callbacks, slots, …), by combining function pointers and parameter values. + For example, to connect the signal to our slot, we call: + client->onMessageReceived.connect(bind(&handleMessageReceived, _1)) + This is essentially saying: when the + onMessageReceived signal is emitted, call + handleMessageReceived, and pass it the first + parameter provided by the slot (which, in this case, is the actual + message received). + + + The implementation of handleMessageReceived should be straightforward: put the To address in place of the From address, and send the message to the server. One + thing to note is that Message::ref represents a + shared pointer to a Message + stanza. Shared pointers behave the same as regular pointers, except that, + when the last copy of the pointer goes away, the object it points to is + deleted as well. Message::ref is in fact a + typedef for boost::shared_ptr<Message>. + Although Swiften tends to prefer the use of the ::ref + notation, you will see both forms used intermixed. + + + + Before moving on to the next step, we are going to rearrange our + code a bit, to make it a bit cleaner. Instead of using global + variables, we are going to create an EchoBot + class with the current code in it. The resulting code can be found + in . + + + Creating an EchoBot class + + + + The important thing to consider in this step are the changes to the signal + connections. Since we are now passing member variables of a class + to the signal, we need to use bind to pass + in the actual object on which this member variable is called as + the first parameter. + + + The only thing we added to this version is the + ClientXMLTracer. This class will dump all + incoming and outgoing XMPP messages to the console, which can be handy + for debugging our bot. - Connecting to the network + Presence Management: Requests + The current version of our EchoBot does what it is supposed to do: + it answers all incoming messages. However, although users can add + the bot to their contact list, they will not see when it is + online, since the bot doesn't do any presence handling yet. In + this section, we explain the different steps involved in adding + presence management, resulting in the code in + . + + + Adding presence management: Requesting the initial roster, and auto-approving incoming subscription requests. + + + + First of all, our bot needs to listen to incoming subscription requests + from users who want to add it to their roster, and automatically + approve them. This is done by connecting to + the onPresenceReceived signal, checking whether + the incoming presence is a subscription request, and if so, + respond to it with an approval (in handlePresenceReceived). + + + + The first version of the XMPP protocol states that a client will not + get any presence + subscriptions until it requests the roster. To make sure we handle + this, we want to make sure our bot requests the roster at login. + After getting the onConnected signal, we + therefore send a + request to retrieve the roster. Swiften's + Request classes correspond to XMPP IQ Get or + Set actions. Swiften provides a set of built-in request classes for + the most common tasks in Swiften/Queries/Requests, + and can be easily extended to use add your own (see ). Requests have an onResponse signal, + which is emitted when a response comes in. This signal has 2 parameters: + the actual response data (the Payload), and an + optional error payload in case there was an error executing the + request. To use a Request class, you construct + it with the correct parameters, connect to the + onResponse signal, and then send the request by + calling send() on it. In this case, we're not + interested in the actual payload of the response (passed as the + first parameter), so we pass it a slot with only the second parameter + (the error payload). When we get the roster back, we send initial + presence to all our subscribers, announcing them we're online. - T + Publishing version information: Responders + Most XMPP clients have support for querying software version information + of a client through + . These clients + send out an IQ-Get request to an entity, which responds with the + requested information. We would like our bot to listen to these + requests, and respond with the correct information. Swiften uses + Responder classes for the purpose of responding + to IQ requests, and are therefore the dual of the + Request clients discussed in the previous section. + + + Adding presence management: Requesting the initial roster, and auto-approving incoming subscription requests. + + + + + Using SoftwareVersionResponder is pretty + straightforward, as can be seen in : + simply construct the responder with the correct + parameters, and it will automatically respond to the incoming + requests. Other Responder classes may provide + signals to notify of incoming requests, or may have some other + behavior. For a detailed explanation of responders, see + . + + + + + Extending Swiften with new payloads: Payloads, Parsers, and Serializers + + Swiften uses abstract datastructures for all the data that is received + and sent over the XMPP network. The declaration of these datastructures + can all be found in Swiften/Elements. For + representing the XMPP stanzas, Swiften uses the + Message, Presence, and + IQ classes. Each stanza can have an arbitrary + amount of child payloads, represented by the + Payload class. A payload typically corresponds + to a (namespaced) child XML element of a stanza; for example, the + <query xmlns="jabber:iq:roster"/> + element used for managing the roster is represented as a + RosterPayload. + + + TODO + + + + Extending Swiften with new queries and responders + TODO + + + + Using Swiften's convenience classes + TODO + + + Bibliography + + + XMPP-TDG + <ulink url="http://oreilly.com/catalog/9780596157197/">XMPP: The + Definitive Guide</ulink> + + Peter + Saint-Andre + + + Kevin + Smith + + + Remko + Tronçon + + + + + XEP-0092 + <ulink url='http://www.xmpp.org/extensions/xep-0092.html'>Software Version</ulink> + + Peter + Saint-Andre + + + diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 9619722..de74150 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -62,7 +62,7 @@ void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::SecurityLabels)) { //chatWindow_->setSecurityLabelsEnabled(true); //chatWindow_->setSecurityLabelsError(); - boost::shared_ptr request(new GetSecurityLabelsCatalogRequest(JID(toJID_.toBare()), iqRouter_)); + GetSecurityLabelsCatalogRequest::ref request = GetSecurityLabelsCatalogRequest::create(JID(toJID_.toBare()), iqRouter_); request->onResponse.connect(boost::bind(&ChatControllerBase::handleSecurityLabelsCatalogResponse, this, _1, _2)); request->send(); //labelsEnabled_ = true; diff --git a/Swift/Controllers/Chat/MUCSearchController.cpp b/Swift/Controllers/Chat/MUCSearchController.cpp index 304de85..dc81031 100644 --- a/Swift/Controllers/Chat/MUCSearchController.cpp +++ b/Swift/Controllers/Chat/MUCSearchController.cpp @@ -63,7 +63,7 @@ void MUCSearchController::handleAddService(const JID& jid, bool userTriggered) { //Set Window to say error this isn't valid return; } - boost::shared_ptr discoInfoRequest(new GetDiscoInfoRequest(jid, iqRouter_)); + GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(jid, iqRouter_); discoInfoRequest->onResponse.connect(boost::bind(&MUCSearchController::handleDiscoInfoResponse, this, _1, _2, jid)); discoInfoRequest->send(); } @@ -79,7 +79,7 @@ void MUCSearchController::handleDiscoInfoResponse(boost::shared_ptr i handleDiscoError(jid, error.get()); return; } - boost::shared_ptr discoItemsRequest(new GetDiscoItemsRequest(jid, iqRouter_)); + GetDiscoItemsRequest::ref discoItemsRequest = GetDiscoItemsRequest::create(jid, iqRouter_); bool mucService = false; bool couldContainServices = false; String name; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 06b231c..ddf9848 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -306,7 +306,7 @@ void MainController::handleConnected() { xmppRosterController_->requestRoster(); - boost::shared_ptr discoInfoRequest(new GetDiscoInfoRequest(JID(), client_->getIQRouter())); + GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(), client_->getIQRouter()); discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2)); discoInfoRequest->send(); diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp index 15ed6a4..e79fad1 100644 --- a/Swift/Controllers/RosterController.cpp +++ b/Swift/Controllers/RosterController.cpp @@ -162,7 +162,7 @@ void RosterController::handleUIEvent(boost::shared_ptr event) { item.setJID(addContactEvent->getJID()); boost::shared_ptr roster(new RosterPayload()); roster->addItem(item); - boost::shared_ptr request(new SetRosterRequest(roster, iqRouter_)); + SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); presenceSender_->requestSubscription(addContactEvent->getJID()); @@ -173,7 +173,7 @@ void RosterController::handleUIEvent(boost::shared_ptr event) { RosterItemPayload item(removeEvent->getJID(), "", RosterItemPayload::Remove); boost::shared_ptr roster(new RosterPayload()); roster->addItem(item); - boost::shared_ptr request(new SetRosterRequest(roster, iqRouter_)); + SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); @@ -186,7 +186,7 @@ void RosterController::handleUIEvent(boost::shared_ptr event) { item.setGroups(xmppRoster_->getGroupsForJID(contact)); boost::shared_ptr roster(new RosterPayload()); roster->addItem(item); - boost::shared_ptr request(new SetRosterRequest(roster, iqRouter_)); + SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); return; @@ -210,7 +210,7 @@ void RosterController::handleUIEvent(boost::shared_ptr event) { item.setGroups(newGroups); boost::shared_ptr roster(new RosterPayload()); roster->addItem(item); - boost::shared_ptr request(new SetRosterRequest(roster, iqRouter_)); + SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); return; diff --git a/Swiften/.gitignore b/Swiften/.gitignore index 9eca6c8..c21d6aa 100644 --- a/Swiften/.gitignore +++ b/Swiften/.gitignore @@ -1,2 +1,3 @@ *.a *.o +Swiften.h diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index 7e55289..5432920 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -22,6 +22,7 @@ #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" #include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include "Swiften/Base/Shared.h" namespace Swift { class IQRouter; diff --git a/Swiften/Client/ClientXMLTracer.h b/Swiften/Client/ClientXMLTracer.h index 8bcb6e7..f3cfd08 100644 --- a/Swiften/Client/ClientXMLTracer.h +++ b/Swiften/Client/ClientXMLTracer.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "Swiften/Client/Client.h" namespace Swift { diff --git a/Swiften/Disco/CapsManager.cpp b/Swiften/Disco/CapsManager.cpp index a5023d3..a9920a2 100644 --- a/Swiften/Disco/CapsManager.cpp +++ b/Swiften/Disco/CapsManager.cpp @@ -69,7 +69,7 @@ void CapsManager::handleDiscoInfoReceived(const JID& from, const String& hash, D } void CapsManager::requestDiscoInfo(const JID& jid, const String& node, const String& hash) { - boost::shared_ptr request(new GetDiscoInfoRequest(jid, node + "#" + hash, iqRouter)); + GetDiscoInfoRequest::ref request = GetDiscoInfoRequest::create(jid, node + "#" + hash, iqRouter); request->onResponse.connect(boost::bind(&CapsManager::handleDiscoInfoReceived, this, jid, hash, _1, _2)); requestedDiscoInfos.insert(hash); request->send(); diff --git a/Swiften/Elements/Presence.h b/Swiften/Elements/Presence.h index 7297339..45638b9 100644 --- a/Swiften/Elements/Presence.h +++ b/Swiften/Elements/Presence.h @@ -22,6 +22,18 @@ namespace Swift { setStatus(status); } + static ref create() { + return ref(new Presence()); + } + + static ref create(const String& status) { + return ref(new Presence(status)); + } + + static ref create(Presence::ref presence) { + return ref(new Presence(*presence)); + } + Type getType() const { return type_; } void setType(Type type) { type_ = type; } diff --git a/Swiften/Elements/RosterPayload.h b/Swiften/Elements/RosterPayload.h index 58c5726..0c987c4 100644 --- a/Swiften/Elements/RosterPayload.h +++ b/Swiften/Elements/RosterPayload.h @@ -4,17 +4,17 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterPayload_H -#define SWIFTEN_RosterPayload_H +#pragma once #include #include #include "Swiften/Elements/RosterItemPayload.h" #include "Swiften/Elements/Payload.h" +#include "Swiften/Base/Shared.h" namespace Swift { - class RosterPayload : public Payload { + class RosterPayload : public Payload, public Shared { public: typedef std::vector RosterItemPayloads; @@ -35,5 +35,3 @@ namespace Swift { RosterItemPayloads items_; }; } - -#endif diff --git a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp index af08a9c..3d814a8 100644 --- a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp +++ b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp @@ -41,7 +41,7 @@ void handleServerDiscoInfoResponse(boost::shared_ptr /*info*/, const void handleConnected() { exitCode = NO_RESPONSE; - boost::shared_ptr discoInfoRequest(new GetDiscoInfoRequest(JID(), client->getIQRouter())); + GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(), client->getIQRouter()); discoInfoRequest->onResponse.connect(handleServerDiscoInfoResponse); discoInfoRequest->send(); } diff --git a/Swiften/Examples/EchoBot/.gitignore b/Swiften/Examples/EchoBot/.gitignore deleted file mode 100644 index 9200f42..0000000 --- a/Swiften/Examples/EchoBot/.gitignore +++ /dev/null @@ -1 +0,0 @@ -EchoBot diff --git a/Swiften/Examples/EchoBot/EchoBot.cpp b/Swiften/Examples/EchoBot/EchoBot.cpp deleted file mode 100644 index 0474287..0000000 --- a/Swiften/Examples/EchoBot/EchoBot.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include -#include - -#include "Swiften/Client/Client.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/Queries/Requests/GetRosterRequest.h" - -using namespace Swift; -using namespace boost; - -class EchoBot { - public: - EchoBot(const JID& jid, const String& pass) { - client = new Client(jid, pass); - client->onConnected.connect(bind(&EchoBot::handleConnected, this)); - client->onMessageReceived.connect(bind(&EchoBot::handleMessageReceived, this, _1)); - client->connect(); - } - - ~EchoBot() { - delete client; - } - - private: - void handleConnected() { - shared_ptr rosterRequest(new GetRosterRequest(client->getIQRouter())); - rosterRequest->onResponse.connect(bind(&EchoBot::handleRosterReceived, this, _2)); - rosterRequest->send(); - } - - void handleRosterReceived(const optional& error) { - if (error) { - std::cerr << "Error receiving roster. Continuing anyway."; - } - client->sendPresence(shared_ptr(new Presence("Send me a message"))); - } - - void handleMessageReceived(shared_ptr message) { - message->setTo(message->getFrom()); - message->setFrom(JID()); - client->sendMessage(message); - } - - private: - Client* client; -}; - -int main(int argc, char* argv[]) { - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " " << std::endl; - return -1; - } - SimpleEventLoop eventLoop; - EchoBot bot(JID(argv[1]), argv[2]); - eventLoop.run(); - return 0; -} diff --git a/Swiften/Examples/EchoBot/SConscript b/Swiften/Examples/EchoBot/SConscript deleted file mode 100644 index fb7749d..0000000 --- a/Swiften/Examples/EchoBot/SConscript +++ /dev/null @@ -1,14 +0,0 @@ -Import("env") - -myenv = env.Clone() -myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) -myenv.MergeFlags(myenv["BOOST_FLAGS"]) -myenv.MergeFlags(myenv.get("SQLITE_FLAGS", {})) -myenv.MergeFlags(myenv["ZLIB_FLAGS"]) -myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) -myenv.MergeFlags(myenv.get("LIBXML_FLAGS", "")) -myenv.MergeFlags(myenv.get("EXPAT_FLAGS", "")) -myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) - -myenv.Program("EchoBot", ["EchoBot.cpp"]) diff --git a/Swiften/Examples/SConscript b/Swiften/Examples/SConscript index 64d1859..61bedfb 100644 --- a/Swiften/Examples/SConscript +++ b/Swiften/Examples/SConscript @@ -6,6 +6,5 @@ SConscript(dirs = [ "SendMessage", "ConnectivityTest", "LinkLocalTool", - "EchoBot", "ParserTester", ]) diff --git a/Swiften/MUC/MUCBookmarkManager.cpp b/Swiften/MUC/MUCBookmarkManager.cpp index 64615e4..0f5f3bb 100644 --- a/Swiften/MUC/MUCBookmarkManager.cpp +++ b/Swiften/MUC/MUCBookmarkManager.cpp @@ -19,7 +19,7 @@ namespace Swift { MUCBookmarkManager::MUCBookmarkManager(IQRouter* iqRouter) { iqRouter_ = iqRouter; ready_ = false; - boost::shared_ptr > request(new GetPrivateStorageRequest(iqRouter_)); + GetPrivateStorageRequest::ref request = GetPrivateStorageRequest::create(iqRouter_); request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksReceived, this, _1, _2)); request->send(); } @@ -106,7 +106,7 @@ void MUCBookmarkManager::flush() { } // Send an iq to save the storage element - boost::shared_ptr > request(new SetPrivateStorageRequest(storage, iqRouter_)); + SetPrivateStorageRequest::ref request = SetPrivateStorageRequest::create(storage, iqRouter_); // FIXME: We should care about the result //request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksSet, this, _1, _2)); request->send(); diff --git a/Swiften/Queries/Request.h b/Swiften/Queries/Request.h index 450e311..9184dea 100644 --- a/Swiften/Queries/Request.h +++ b/Swiften/Queries/Request.h @@ -21,6 +21,9 @@ namespace Swift { class Request : public IQHandler, public boost::enable_shared_from_this { public: + void send(); + + protected: Request( IQ::Type type, const JID& receiver, @@ -31,9 +34,6 @@ namespace Swift { const JID& receiver, IQRouter* router); - void send(); - - protected: virtual void setPayload(boost::shared_ptr p) { payload_ = p; } diff --git a/Swiften/Queries/Requests/GetDiscoInfoRequest.h b/Swiften/Queries/Requests/GetDiscoInfoRequest.h index 9ec1050..d1ed279 100644 --- a/Swiften/Queries/Requests/GetDiscoInfoRequest.h +++ b/Swiften/Queries/Requests/GetDiscoInfoRequest.h @@ -10,8 +10,17 @@ #include "Swiften/Elements/DiscoInfo.h" namespace Swift { - class GetDiscoInfoRequest : public GenericRequest { + class GetDiscoInfoRequest : public GenericRequest, public Shared { public: + static ref create(const JID& jid, IQRouter* router) { + return ref(new GetDiscoInfoRequest(jid, router)); + } + + static ref create(const JID& jid, const String& node, IQRouter* router) { + return ref(new GetDiscoInfoRequest(jid, node, router)); + } + + private: GetDiscoInfoRequest(const JID& jid, IQRouter* router) : GenericRequest(IQ::Get, jid, boost::shared_ptr(new DiscoInfo()), router) { } diff --git a/Swiften/Queries/Requests/GetDiscoItemsRequest.h b/Swiften/Queries/Requests/GetDiscoItemsRequest.h index 453eab4..ed565ac 100644 --- a/Swiften/Queries/Requests/GetDiscoItemsRequest.h +++ b/Swiften/Queries/Requests/GetDiscoItemsRequest.h @@ -10,8 +10,13 @@ #include "Swiften/Elements/DiscoItems.h" namespace Swift { - class GetDiscoItemsRequest : public GenericRequest { + class GetDiscoItemsRequest : public GenericRequest, public Shared { public: + static ref create(const JID& jid, IQRouter* router) { + return ref(new GetDiscoItemsRequest(jid, router)); + } + + private: GetDiscoItemsRequest(const JID& jid, IQRouter* router) : GenericRequest(IQ::Get, jid, boost::shared_ptr(new DiscoItems()), router) { } diff --git a/Swiften/Queries/Requests/GetPrivateStorageRequest.h b/Swiften/Queries/Requests/GetPrivateStorageRequest.h index d44d5d8..b593495 100644 --- a/Swiften/Queries/Requests/GetPrivateStorageRequest.h +++ b/Swiften/Queries/Requests/GetPrivateStorageRequest.h @@ -17,6 +17,13 @@ namespace Swift { template class GetPrivateStorageRequest : public Request { public: + typedef boost::shared_ptr > ref; + + static ref create(IQRouter* router) { + return ref(new GetPrivateStorageRequest(router)); + } + + private: GetPrivateStorageRequest(IQRouter* router) : Request(IQ::Get, JID(), boost::shared_ptr(new PrivateStorage(boost::shared_ptr(new PAYLOAD_TYPE()))), router) { } diff --git a/Swiften/Queries/Requests/GetRosterRequest.h b/Swiften/Queries/Requests/GetRosterRequest.h index 59cefe4..271b2fb 100644 --- a/Swiften/Queries/Requests/GetRosterRequest.h +++ b/Swiften/Queries/Requests/GetRosterRequest.h @@ -8,10 +8,16 @@ #include "Swiften/Queries/GenericRequest.h" #include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Base/Shared.h" namespace Swift { - class GetRosterRequest : public GenericRequest { + class GetRosterRequest : public GenericRequest, public Shared { public: + static ref create(IQRouter* router) { + return ref(new GetRosterRequest(router)); + } + + private: GetRosterRequest(IQRouter* router) : GenericRequest(IQ::Get, JID(), boost::shared_ptr(new RosterPayload()), router) { } diff --git a/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h index 41225fb..ec04f80 100644 --- a/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h +++ b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h @@ -8,10 +8,16 @@ #include "Swiften/Queries/GenericRequest.h" #include "Swiften/Elements/SecurityLabelsCatalog.h" +#include "Swiften/Base/Shared.h" namespace Swift { - class GetSecurityLabelsCatalogRequest : public GenericRequest { + class GetSecurityLabelsCatalogRequest : public GenericRequest, public Shared { public: + static ref create(const JID& recipient, IQRouter* router) { + return ref(new GetSecurityLabelsCatalogRequest(recipient, router)); + } + + private: GetSecurityLabelsCatalogRequest( const JID& recipient, IQRouter* router) : diff --git a/Swiften/Queries/Requests/GetVCardRequest.h b/Swiften/Queries/Requests/GetVCardRequest.h index f369cdc..2c40cd1 100644 --- a/Swiften/Queries/Requests/GetVCardRequest.h +++ b/Swiften/Queries/Requests/GetVCardRequest.h @@ -13,6 +13,11 @@ namespace Swift { class GetVCardRequest : public GenericRequest, public Shared { public: + static ref create(const JID& jid, IQRouter* router) { + return ref(new GetVCardRequest(jid, router)); + } + + private: GetVCardRequest(const JID& jid, IQRouter* router) : GenericRequest(IQ::Get, jid, boost::shared_ptr(new VCard()), router) { } }; diff --git a/Swiften/Queries/Requests/SetPrivateStorageRequest.h b/Swiften/Queries/Requests/SetPrivateStorageRequest.h index ebdfca8..1931f3a 100644 --- a/Swiften/Queries/Requests/SetPrivateStorageRequest.h +++ b/Swiften/Queries/Requests/SetPrivateStorageRequest.h @@ -17,6 +17,13 @@ namespace Swift { template class SetPrivateStorageRequest : public Request { public: + typedef boost::shared_ptr > ref; + + static ref create(boost::shared_ptr payload, IQRouter* router) { + return ref(new SetPrivateStorageRequest(payload, router)); + } + + private: SetPrivateStorageRequest(boost::shared_ptr payload, IQRouter* router) : Request(IQ::Set, JID(), boost::shared_ptr(new PrivateStorage(payload)), router) { } diff --git a/Swiften/Queries/Requests/SetRosterRequest.h b/Swiften/Queries/Requests/SetRosterRequest.h index 1f47cfe..7b1bf8c 100644 --- a/Swiften/Queries/Requests/SetRosterRequest.h +++ b/Swiften/Queries/Requests/SetRosterRequest.h @@ -11,10 +11,16 @@ #include "Swiften/Queries/Request.h" #include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Base/Shared.h" namespace Swift { - class SetRosterRequest : public Request { + class SetRosterRequest : public Request, public Shared { public: + static ref create(RosterPayload::ref payload, IQRouter* router) { + return ref(new SetRosterRequest(payload, router)); + } + + private: SetRosterRequest(boost::shared_ptr payload, IQRouter* router) : Request(IQ::Set, JID(), boost::shared_ptr(payload), router) { } diff --git a/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp b/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp index d90a114..fe8b0a0 100644 --- a/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp +++ b/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp @@ -45,8 +45,8 @@ class GetPrivateStorageRequestTest : public CppUnit::TestFixture } void testSend() { - GetPrivateStorageRequest request(router); - request.send(); + GetPrivateStorageRequest::ref request = GetPrivateStorageRequest::create(router); + request->send(); CPPUNIT_ASSERT_EQUAL(1, static_cast(channel->iqs_.size())); CPPUNIT_ASSERT_EQUAL(JID(), channel->iqs_[0]->getTo()); @@ -58,9 +58,9 @@ class GetPrivateStorageRequestTest : public CppUnit::TestFixture } void testHandleResponse() { - GetPrivateStorageRequest testling(router); - testling.onResponse.connect(boost::bind(&GetPrivateStorageRequestTest::handleResponse, this, _1, _2)); - testling.send(); + GetPrivateStorageRequest::ref testling = GetPrivateStorageRequest::create(router); + testling->onResponse.connect(boost::bind(&GetPrivateStorageRequestTest::handleResponse, this, _1, _2)); + testling->send(); channel->onIQReceived(createResponse("test-id", "foo")); CPPUNIT_ASSERT_EQUAL(1, static_cast(responses.size())); @@ -68,9 +68,9 @@ class GetPrivateStorageRequestTest : public CppUnit::TestFixture } void testHandleResponse_Error() { - GetPrivateStorageRequest testling(router); - testling.onResponse.connect(boost::bind(&GetPrivateStorageRequestTest::handleResponse, this, _1, _2)); - testling.send(); + GetPrivateStorageRequest::ref testling = GetPrivateStorageRequest::create(router); + testling->onResponse.connect(boost::bind(&GetPrivateStorageRequestTest::handleResponse, this, _1, _2)); + testling->send(); channel->onIQReceived(createError("test-id")); CPPUNIT_ASSERT_EQUAL(0, static_cast(responses.size())); diff --git a/Swiften/Roster/XMPPRosterController.cpp b/Swiften/Roster/XMPPRosterController.cpp index dca74c0..7743ec8 100644 --- a/Swiften/Roster/XMPPRosterController.cpp +++ b/Swiften/Roster/XMPPRosterController.cpp @@ -29,7 +29,7 @@ XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRoster* xmppR void XMPPRosterController::requestRoster() { xmppRoster_->clear(); - boost::shared_ptr rosterRequest(new GetRosterRequest(iqRouter_)); + GetRosterRequest::ref rosterRequest = GetRosterRequest::create(iqRouter_); rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1)); rosterRequest->send(); } diff --git a/Swiften/SConscript b/Swiften/SConscript index c5ad9a6..7665fb0 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -1,3 +1,5 @@ +import os + Import("env") ################################################################################ @@ -244,3 +246,19 @@ if env["SCONS_STAGE"] == "build" : File("StringCodecs/UnitTest/PBKDF2Test.cpp"), File("VCards/UnitTest/VCardManagerTest.cpp"), ]) + + # Generate the Swiften header + swiften_header = "#pragma once\n" + top_path = env.Dir("..").abspath + public_dirs = ["Queries", "Client", "Elements"] + for public_dir in public_dirs : + for root, dirs, files in os.walk(env.Dir(public_dir).abspath) : + if root.endswith("UnitTest") : + continue + for file in files : + if not file.endswith(".h") : + continue + swiften_header += "#include \"" + os.path.relpath(os.path.join(root, file), top_path) + "\"\n" + for file in ["EventLoop/SimpleEventLoop.h"] : + swiften_header += "#include \"Swiften/" + file + "\"\n" + swiften_env.WriteVal("Swiften.h", swiften_env.Value(swiften_header)) \ No newline at end of file diff --git a/Swiften/VCards/VCardManager.cpp b/Swiften/VCards/VCardManager.cpp index 673b937..c189717 100644 --- a/Swiften/VCards/VCardManager.cpp +++ b/Swiften/VCards/VCardManager.cpp @@ -34,7 +34,7 @@ void VCardManager::requestVCard(const JID& requestedJID) { if (requestedVCards.find(jid) != requestedVCards.end()) { return; } - GetVCardRequest::ref request(new GetVCardRequest(jid, iqRouter)); + GetVCardRequest::ref request = GetVCardRequest::create(jid, iqRouter); request->onResponse.connect(boost::bind(&VCardManager::handleVCardReceived, this, jid, _1, _2)); request->send(); requestedVCards.insert(jid); -- cgit v0.10.2-6-g49f6