Changeset - e4800fcf0f17
[Not reviewed]
Merge
! ! !
Vitaly Takmazov - 13 years ago 2012-03-06 09:09:44
vitalyster@gmail.com
Merge branch 'master' of github.com:vitalyster/libtransport
69 files changed:
ChangeLog
18
1
Changeset was too big and was cut off... Show full diff anyway
0 comments (0 inline, 0 general)
CMakeLists.txt
Show inline comments
 
@@ -6,8 +6,12 @@ set(CMAKE_MODULE_PATH "cmake_modules")
 
set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(cppunit)
 

	
 
if (WIN32)
 
ADD_SUBDIRECTORY(msvc-deps)
 
else()
 
set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(sqlite3)
 
endif()
 

	
 
set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(mysql)
 
@@ -29,16 +33,18 @@ find_package(event)
 
set(Swiften_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(Swiften REQUIRED)
 

	
 
if (NOT WIN32)
 
set(openssl_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(openssl REQUIRED)
 
endif()
 

	
 
set(Boost_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
if (WIN32)
 
set(Boost_USE_STATIC_LIBS        ON)
 
set(Boost_USE_STATIC_LIBS      ON)
 
set(Boost_USE_MULTITHREADED      ON)
 
set(Boost_USE_STATIC_RUNTIME    OFF)
 
endif()
 
find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED)
 
find_package(Boost COMPONENTS program_options date_time system filesystem regex  signals REQUIRED)
 
message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}")
 

	
 
set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
@@ -56,6 +62,11 @@ find_package(event)
 
set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(pqxx)
 

	
 
if (NOT WIN32)
 
set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules")
 
find_package(dbus)
 
endif()
 

	
 
find_package(Doxygen)
 

	
 
INCLUDE(FindQt4)
 
@@ -72,7 +83,10 @@ if (SPECTRUM_VERSION)
 
	ADD_DEFINITIONS(-DSPECTRUM_VERSION="${SPECTRUM_VERSION}")
 
else (SPECTRUM_VERSION)
 
	if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
 
		execute_process(COMMAND git "--git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git" rev-parse --short HEAD
 
		if (NOT GIT_EXECUTABLE)
 
		set (GIT_EXECUTABLE git)
 
		endif()
 
		execute_process(COMMAND ${GIT_EXECUTABLE} "--git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git" rev-parse --short HEAD
 
						OUTPUT_VARIABLE GIT_REVISION
 
						OUTPUT_STRIP_TRAILING_WHITESPACE
 
		)
 
@@ -91,8 +105,15 @@ if (SQLITE3_FOUND)
 
	include_directories(${SQLITE3_INCLUDE_DIR})
 
	message("SQLite3           : yes")
 
else (SQLITE3_FOUND)
 
if (WIN32)
 
	ADD_DEFINITIONS(-DWITH_SQLITE)
 
	include_directories(msvc-deps/sqlite3)
 
	set (SQLITE3_LIBRARIES "${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3/sqlite3.lib")
 
	message("SQLite3           : bundled")
 
else()
 
	set(SQLITE3_LIBRARIES "")
 
	message("SQLite3           : no")
 
endif()
 
endif (SQLITE3_FOUND)
 

	
 
if (MYSQL_FOUND)
 
@@ -145,23 +166,35 @@ if (PROTOBUF_FOUND)
 
		message("IRC plugin        : no (install libCommuni and libprotobuf-dev)")
 
	endif()
 

	
 
if (NOT WIN32)
 
	message("Frotz plugin      : yes")
 
	message("SMSTools3 plugin  : yes")
 
else()
 
	message("Frotz plugin      : no")
 
	message("SMSTools3 plugin  : no")
 
	if(${LIBDBUSGLIB_FOUND})
 
		message("Skype plugin      : yes")
 
		include_directories(${LIBDBUSGLIB_INCLUDE_DIRS})
 
	else()
 
		message("Skype plugin      : no (install dbus-glib-devel)")
 
	endif()
 
endif()
 

	
 
else()
 
	message("Network plugins   : no (install libprotobuf-dev)")
 
	message("Libpurple plugin  : no (install libpurple and libprotobuf-dev)")
 
	message("IRC plugin        : no (install libircclient-qt and libprotobuf-dev)")
 
	message("Frotz plugin      : no (install libprotobuf-dev)")
 
	message("SMSTools3 plugin  : no (install libprotobuf-dev)")
 
endif()
 

	
 
if (LOG4CXX_FOUND)
 
	message("Logging           : yes")
 
	include_directories(${LOG4CXX_INCLUDE_DIR})
 
else()
 
	message(FATAL_ERROR "Logging           : no (install log4cxx-devel)")
 
endif()
 

	
 
if (WIN32)
 
ADD_DEFINITIONS(-DLOG4CXX_STATIC)
 
ADD_DEFINITIONS(-D_WIN32_WINNT=0x501)
 
ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN)
 
endif()
 
@@ -197,7 +230,10 @@ include_directories(include)
 
include_directories(${EVENT_INCLUDE_DIRS})
 
include_directories(${SWIFTEN_INCLUDE_DIR})
 
include_directories(${Boost_INCLUDE_DIRS})
 

	
 
if (NOT WIN32)
 
include_directories(${OPENSSL_INCLUDE_DIR})
 
endif()
 

	
 
ADD_SUBDIRECTORY(src)
 
ADD_SUBDIRECTORY(plugin)
ChangeLog
Show inline comments
 
Version 2.0.0-beta  (X-X-X):
 
Version 2.0.0-beta (2012-02-28):
 
	General:
 
	* Added PostreSQL support (thanks to Jadestorm).
 
	* Added XEP-0100 (Gateway interaction) support.
 
	* Send presences only "from" bare JID (fixed bug with buddies appearing
 
	  twice in the roster and potential unregistering issues).
 
	* Fixed potential MySQL/SQLite3 deadlocks.
 
	* Fixed disconnecting in server-mode when client does not send unavailable
 
	  presence before disconnection.
 
	* Fixed crash in server-mode when client send its custom jabber:iq:storage
 
	  payload.
 
	* Fixed registration from Pidgin.
 
	* Unsubscribe presence sent to some buddy doesn't disconnect the account.
 
	* Remote Roster requests are not sent to resources, but to bare JID.
 
	* Added automatic reconnection in case of non-fatal error.
 
	* Added more error messages.
 

	
 
	Skype:
 
	* Initial support for Skype added, read more on
 
	  http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_Skype_backend
 

	
 
	SMSTools3:
 
	* Initial support for SMSTools3, read more on
 
	http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_SMSTools3_backend
 

	
 
version 2.0.0 alpha (2011-12-06):
 
	General:
 
	* First Spectrum 2.0.0 alpha release, check more on
README.win32
Show inline comments
 
new file 100644
 
Prerequisites
 
=============
 
 
1. Microsoft Visual C++ 2010 Express or higher edition (http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express)
 
2. Git for Windows (http://code.google.com/p/msysgit/downloads/list)
 
3. CMake 2.8 or newer (http://www.cmake.org/cmake/resources/software.html)
 
 
Libraries
 
=========
 
3. Swiften library and Python for run scons (http://swift.im/git/swift)
 
4. Boost 1.48 or newer (http://sourceforge.net/projects/boost/files/boost/1.49.0/)
 
5. Google ProtoBuf library (http://code.google.com/p/protobuf/downloads/list)
 
6. Apache log4cxx, apr, apr-util (http://logging.apache.org/log4cxx/download.html)
 
 
 
Environment
 
===========
 
 
To create spectrum build environment do:
 
 
0. Create directory where we'll install all dependencies, e.g. C:\env-msvc-x64
 
Assuming you have git, python and cmake in %PATH%, 
 
launch "Visual Studio 2010 command prompt" or
 
"Visual Studio 2010(x64) command prompt", depends on your target (Windows x86 or Windows x86_64).
 
1. unpack and build boost libraries:
 
 
	bootstrap.bat
 
	b2.exe --without-mpi --without-python
 
	b2.exe --without-mpi --without-python install --prefix=C:\env-msvc-x64
 
 
2. clone swift repository and build it. Don't forget to point it to our env directory:
 
 
	git clone http://swift.im/git/swift
 
	cd swift
 
	echo boost_includedir="c:/env-msvc-x64/include/boost-1_48" > config.py
 
	echo boost_libdir="c:/env-msvc-x64/lib" >> config.py 
 
	scons.bat debug=no SWIFTEN_INSTALLDIR=C:\env-msvc-x64
 
	scons.bat debug=no SWIFTEN_INSTALLDIR=C:\env-msvc-x64 C:\env-msvc-x64
 
 
TODO: fix in upstream
 
You may need manually copy compiled 3rdParty libs to C:\env-msvc-x64\lib\3rdParty\Expat, 
 
C:\env-msvc-x64\lib\3rdParty\LibIDN, C:\env-msvc-x64\lib\3rdParty\Zlib
 
 
3. unpack and compile protobuf as described in its documentation. 
 
 
Run extract_includes.bat in vsprojects/ directory and move resulting google/ directory to our C:\env-msvc-x64\include
 
 
Move protoc.exe to C:\env-msvc-x64\bin\ and libprotobuf.lib to C:\env-msvc-x64\lib
 
 
4. unpack and compile log4cxx, apr, apr-util as described here: 
 
	http://www.lextm.com/2010/09/how-to-build-log4cxx-in-visual-studio.html
 
Also you need to make output type="Static Library" and add LOG4CXX_STATIC in Preprocessor Definitions of log4cxx vsproject.
 
Move include/log4cxx and resulting log4cxx.lib to C:\env-msvc-x64\include and C:\env-msvc-x64\lib
 
 
5. You're ready! :) Clone libtransport and compile it as:
 
	set CMAKE_INCLUDE_PATH=C:\env-msvc-x64\include
 
	cmake . -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=C:\env-msvc-x64 -DGIT_EXECUTABLE="c:\Program Files (x86)\git\bin\git.exe"
 
	nmake
 
 
TODO: libpurple_backend compilation
backends/CMakeLists.txt
Show inline comments
 
@@ -7,8 +7,14 @@ if (PROTOBUF_FOUND)
 
		ADD_SUBDIRECTORY(libcommuni)
 
	endif()
 

	
 
	ADD_SUBDIRECTORY(template)
 

	
 
if (NOT WIN32)
 
	ADD_SUBDIRECTORY(smstools3)
 
	ADD_SUBDIRECTORY(frotz)
 
	if (${LIBDBUSGLIB_FOUND})
 
		ADD_SUBDIRECTORY(skype)
 
	endif()
 
endif()
 

	
 
endif()
backends/frotz/CMakeLists.txt
Show inline comments
 
@@ -6,7 +6,7 @@ FILE(GLOB SRC *.c *.cpp)
 
 
ADD_EXECUTABLE(spectrum2_frotz_backend ${SRC})
 
 
target_link_libraries(spectrum2_frotz_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
 
target_link_libraries(spectrum2_frotz_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
 
 
INSTALL(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION bin)
 
backends/libcommuni/CMakeLists.txt
Show inline comments
 
@@ -4,7 +4,7 @@ FILE(GLOB HEADERS *.h)
 
QT4_WRAP_CPP(SRC ${HEADERS})
 
ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC})
 
 
target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport-plugin transport pthread)
 
target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread)
 
 
INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin)
 
backends/libpurple/main.cpp
Show inline comments
 
@@ -915,6 +915,41 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
 
			}
 
		}
 

	
 
		void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &pasword) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (!account) {
 
				return;
 
			}
 

	
 
			PurpleConnection *gc = purple_account_get_connection(account);
 
			GHashTable *comps = NULL;
 

	
 
			// Check if the PurpleChat is not stored in buddy list
 
			PurpleChat *chat = purple_blist_find_chat(account, room.c_str());
 
			if (chat) {
 
				comps = purple_chat_get_components(chat);
 
			}
 
			else if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) {
 
				comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, room.c_str());
 
			}
 

	
 
			LOG4CXX_INFO(logger, user << ": Joining the room " << room);
 
			if (comps) {
 
				serv_join_chat(gc, comps);
 
				g_hash_table_destroy(comps);
 
			}
 
		}
 

	
 
		void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
 
			PurpleAccount *account = m_sessions[user];
 
			if (!account) {
 
				return;
 
			}
 

	
 
			PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room.c_str(), account);
 
			purple_conversation_destroy(conv);
 
		}
 

	
 
		void handleFTStartRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) {
 
			PurpleXfer *xfer = m_unhandledXfers[user + fileName + buddyName];
 
			if (xfer) {
backends/skype/CMakeLists.txt
Show inline comments
 
new file 100644
 
cmake_minimum_required(VERSION 2.6)
 
FILE(GLOB SRC *.cpp)
 
 
ADD_EXECUTABLE(spectrum2_skype_backend ${SRC})
 
 
target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES})
 
 
INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin)
 
backends/skype/main.cpp
Show inline comments
 
new file 100644
 
#include "glib.h"
 
#include <iostream>
 

	
 
#include "transport/config.h"
 
#include "transport/transport.h"
 
#include "transport/usermanager.h"
 
#include "transport/logger.h"
 
#include "transport/sqlite3backend.h"
 
#include "transport/userregistration.h"
 
#include "transport/user.h"
 
#include "transport/storagebackend.h"
 
#include "transport/rostermanager.h"
 
#include "transport/conversation.h"
 
#include "transport/networkplugin.h"
 
#include <boost/filesystem.hpp>
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
// #include "valgrind/memcheck.h"
 
#include "malloc.h"
 
#include <dbus-1.0/dbus/dbus-glib-lowlevel.h>
 

	
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = Logger::getLogger("backend");
 

	
 
using namespace Transport;
 

	
 
class SpectrumNetworkPlugin;
 

	
 

	
 
SpectrumNetworkPlugin *np;
 

	
 
static gboolean nodaemon = FALSE;
 
static gchar *logfile = NULL;
 
static gchar *lock_file = NULL;
 
static gchar *host = NULL;
 
static int port = 10000;
 
static gboolean ver = FALSE;
 
static gboolean list_purple_settings = FALSE;
 

	
 
int m_sock;
 
static int writeInput;
 

	
 
static GOptionEntry options_entries[] = {
 
	{ "nodaemon", 'n', 0, G_OPTION_ARG_NONE, &nodaemon, "Disable background daemon mode", NULL },
 
	{ "logfile", 'l', 0, G_OPTION_ARG_STRING, &logfile, "Set file to log", NULL },
 
	{ "pidfile", 'p', 0, G_OPTION_ARG_STRING, &lock_file, "File where to write transport PID", NULL },
 
	{ "version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Shows Spectrum version", NULL },
 
	{ "list-purple-settings", 's', 0, G_OPTION_ARG_NONE, &list_purple_settings, "Lists purple settings which can be used in config file", NULL },
 
	{ "host", 'h', 0, G_OPTION_ARG_STRING, &host, "Host to connect to", NULL },
 
	{ "port", 'p', 0, G_OPTION_ARG_INT, &port, "Port to connect to", NULL },
 
	{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL }
 
};
 

	
 
DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data);
 

	
 
static pbnetwork::StatusType getStatus(const std::string &st) {
 
	pbnetwork::StatusType status = pbnetwork::STATUS_ONLINE;
 
	if (st == "SKYPEOUT" || st == "OFFLINE") {
 
		status = pbnetwork::STATUS_NONE;
 
	}
 
	else if (st == "DND") {
 
		status = pbnetwork::STATUS_DND;
 
	}
 
	else if (st == "NA") {
 
		status = pbnetwork::STATUS_XA;
 
	}
 
	else if (st == "AWAY") {
 
		status = pbnetwork::STATUS_AWAY;
 
	}
 
	return status;
 
}
 

	
 
class Skype {
 
	public:
 
		Skype(const std::string &user, const std::string &username, const std::string &password);
 
		~Skype() { logout(); }
 
		void login();
 
		void logout();
 
		std::string send_command(const std::string &message);
 

	
 
		const std::string &getUser() {
 
			return m_user;
 
		}
 

	
 
		const std::string &getUsername() {
 
			return m_username;
 
		}
 

	
 
		bool createDBusProxy();
 
		bool loadSkypeBuddies();
 

	
 
	private:
 
		std::string m_username;
 
		std::string m_password;
 
		GPid m_pid;
 
		DBusGConnection *m_connection;
 
		DBusGProxy *m_proxy;
 
		std::string m_user;
 
		int m_timer;
 
		int m_counter;
 
		int fd_output;
 
};
 

	
 
class SpectrumNetworkPlugin : public NetworkPlugin {
 
	public:
 
		SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() {
 
			this->config = config;
 
			LOG4CXX_INFO(logger, "Starting the backend.");
 
		}
 

	
 
		~SpectrumNetworkPlugin() {
 
			for (std::map<Skype *, std::string>::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) {
 
				delete (*it).first;
 
			}
 
		}
 

	
 
		void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
			std::string name = legacyName;
 
			name = name.substr(name.find(".") + 1);
 
			LOG4CXX_INFO(logger,  "Creating account with name '" << name << "'");
 

	
 
			Skype *skype = new Skype(user, name, password);
 
			m_sessions[user] = skype;
 
			m_accounts[skype] = user;
 

	
 
			skype->login();
 
		}
 

	
 
		void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
			Skype *skype = m_sessions[user];
 
			if (skype) {
 
				skype->logout();
 
				exit(1);
 
			}
 
		}
 

	
 
		void handleStatusChangeRequest(const std::string &user, int status, const std::string &statusMessage) {
 
			Skype *skype = m_sessions[user];
 
			if (!skype)
 
				return;
 

	
 
			std::string st;
 
			switch(status) {
 
				case Swift::StatusShow::Away: {
 
					st = "AWAY";
 
					break;
 
				}
 
				case Swift::StatusShow::DND: {
 
					st = "DND";
 
					break;
 
				}
 
				case Swift::StatusShow::XA: {
 
					st = "NA";
 
					break;
 
				}
 
				case Swift::StatusShow::None: {
 
					break;
 
				}
 
				case pbnetwork::STATUS_INVISIBLE:
 
					st = "INVISIBLE";
 
					break;
 
				default:
 
					st = "ONLINE";
 
					break;
 
			}
 
			skype->send_command("SET USERSTATUS " + st);
 

	
 
			if (!statusMessage.empty()) {
 
				skype->send_command("SET PROFILE MOOD_TEXT " + statusMessage);
 
			}
 
		}
 

	
 
		void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) {
 
			Skype *skype = m_sessions[user];
 
			if (skype) {
 
				skype->send_command("MESSAGE " + legacyName + " " + message);
 
			}
 
			
 
		}
 

	
 
		void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) {
 
			Skype *skype = m_sessions[user];
 
			if (skype) {
 
				std::string name = legacyName;
 
				if (name.find("skype.") == 0) {
 
					name = name.substr(6);
 
				}
 
				std::string photo;
 
				gchar *filename = NULL;
 
				gchar *new_filename = NULL;
 
				gchar *image_data = NULL;
 
				gsize image_data_len = 0;
 
				gchar *ret;
 
				int fh;
 
				GError *error;
 
				const gchar *userfiles[] = {"user256", "user1024", "user4096", "user16384", "user32768", "user65536",
 
											"profile256", "profile1024", "profile4096", "profile16384", "profile32768", 
 
											NULL};
 
				char *username = g_strdup_printf("\x03\x10%s", name.c_str());
 
				for (fh = 0; userfiles[fh]; fh++) {
 
					filename = g_strconcat("/tmp/skype/", skype->getUsername().c_str(), "/", skype->getUsername().c_str(), "/", userfiles[fh], ".dbb", NULL);
 
					std::cout << "getting filename:" << filename << "\n";
 
					if (g_file_get_contents(filename, &image_data, &image_data_len, NULL))
 
					{
 
						std::cout << "got\n";
 
						char *start = (char *)memmem(image_data, image_data_len, username, strlen(username)+1);
 
						if (start != NULL)
 
						{
 
							char *next = image_data;
 
							char *last = next;
 
							//find last index of l33l
 
							while ((next = (char *)memmem(next+4, start-next-4, "l33l", 4)))
 
							{
 
								last = next;
 
							}
 
							start = last;
 
							if (start != NULL)
 
							{
 
								char *img_start;
 
								//find end of l33l block
 
								char *end = (char *)memmem(start+4, image_data+image_data_len-start-4, "l33l", 4);
 
								if (!end) end = image_data+image_data_len;
 
								
 
								//look for start of JPEG block
 
								img_start = (char *)memmem(start, end-start, "\xFF\xD8", 2);
 
								if (img_start)
 
								{
 
									//look for end of JPEG block
 
									char *img_end = (char *)memmem(img_start, end-img_start, "\xFF\xD9", 2);
 
									if (img_end)
 
									{
 
										image_data_len = img_end - img_start + 2;
 
										photo = std::string(img_start, image_data_len);
 
									}
 
								}
 
							}
 
						}
 
						g_free(image_data);
 
					}
 
					g_free(filename);
 
				}
 
				g_free(username);
 
				
 
				std::string alias = "";
 
				std::cout << skype->getUsername() << " " << name << "\n";
 
				if (skype->getUsername() == name) {
 
					alias = skype->send_command("GET PROFILE FULLNAME");
 
					alias = alias.substr(17);
 
				}
 
				handleVCard(user, id, legacyName, "", alias, photo);
 
			}
 
		}
 

	
 
		void sendData(const std::string &string) {
 
			write(m_sock, string.c_str(), string.size());
 
// 			if (writeInput == 0)
 
// 				writeInput = purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL);
 
		}
 

	
 
		void handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname) {
 
		}
 

	
 
		void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
 
		}
 

	
 
		void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
 

	
 
		}
 

	
 
		void handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) {
 

	
 
		}
 

	
 
		void handleTypingRequest(const std::string &user, const std::string &buddyName) {
 

	
 
		}
 

	
 
		void handleTypedRequest(const std::string &user, const std::string &buddyName) {
 

	
 
		}
 

	
 
		void handleStoppedTypingRequest(const std::string &user, const std::string &buddyName) {
 

	
 
		}
 

	
 
		void handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message) {
 

	
 
		}
 

	
 
		std::map<std::string, Skype *> m_sessions;
 
		std::map<Skype *, std::string> m_accounts;
 
		std::map<std::string, unsigned int> m_vcards;
 
		Config *config;
 
		
 
};
 

	
 

	
 
Skype::Skype(const std::string &user, const std::string &username, const std::string &password) {
 
	m_username = username;
 
	m_user = user;
 
	m_password = password;
 
	m_pid = 0;
 
	m_connection = 0;
 
	m_proxy = 0;
 
	m_timer = -1;
 
	m_counter = 0;
 
}
 

	
 

	
 
static gboolean load_skype_buddies(gpointer data) {
 
	Skype *skype = (Skype *) data;
 
	return skype->loadSkypeBuddies();
 
}
 

	
 
bool Skype::createDBusProxy() {
 
	if (m_proxy == NULL) {
 
		LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api.");
 
		m_counter++;
 

	
 
		GError *error = NULL;
 
		m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, "com.Skype.API", "/com/Skype", "com.Skype.API", &error);
 
		if (m_proxy == NULL && error != NULL) {
 
			LOG4CXX_INFO(logger,  m_username << ":" << error->message);
 

	
 
			if (m_counter == 15) {
 
				np->handleDisconnected(m_user, 0, error->message);
 
				logout();
 
				g_error_free(error);
 
				return FALSE;
 
			}
 
			g_error_free(error);
 
		}
 

	
 
		if (m_proxy) {
 
			LOG4CXX_INFO(logger, "Proxy created.");
 
			DBusObjectPathVTable vtable;
 
			vtable.message_function = &skype_notify_handler;
 
			dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this);
 

	
 
			m_counter = 0;
 
			m_timer = g_timeout_add_seconds(1, load_skype_buddies, this);
 
			return FALSE;
 
		}
 
		return TRUE;
 
	}
 
	return FALSE;
 
}
 

	
 
static gboolean create_dbus_proxy(gpointer data) {
 
	Skype *skype = (Skype *) data;
 
	return skype->createDBusProxy();
 
}
 

	
 
void Skype::login() {
 
	boost::filesystem::path	path(std::string("/tmp/skype/") + m_username);
 
	if (!boost::filesystem::exists(path)) {
 
		boost::filesystem::create_directories(path);
 
		boost::filesystem::path	path2(std::string("/tmp/skype/") + m_username + "/" + m_username );
 
		boost::filesystem::create_directories(path2);
 
	}
 

	
 
	std::string shared_xml = "<?xml version=\"1.0\"?>\n"
 
							"<config version=\"1.0\" serial=\"28\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
 
							"<UI>\n"
 
								"<Installed>2</Installed>\n"
 
								"<Language>en</Language>\n"
 
							"</UI>\n"
 
							"</config>\n";
 
	g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL);
 

	
 
	std::string config_xml = "<?xml version=\"1.0\"?>\n"
 
							"<config version=\"1.0\" serial=\"7\" timestamp=\"" + boost::lexical_cast<std::string>(time(NULL)) + ".0\">\n"
 
								"<Lib>\n"
 
									"<Account>\n"
 
									"<IdleTimeForAway>30000000</IdleTimeForAway>\n"
 
									"<IdleTimeForNA>300000000</IdleTimeForNA>\n"
 
									"<LastUsed>" + boost::lexical_cast<std::string>(time(NULL)) + "</LastUsed>\n"
 
									"</Account>\n"
 
								"</Lib>\n"
 
								"<UI>\n"
 
									"<API>\n"
 
									"<Authorizations>Spectrum</Authorizations>\n"
 
									"<BlockedPrograms></BlockedPrograms>\n"
 
									"</API>\n"
 
								"</UI>\n"
 
							"</config>\n";
 
	g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL);
 

	
 
	std::string db_path = std::string("/tmp/skype/") + m_username;
 
	char *db = (char *) malloc(db_path.size() + 1);
 
	strcpy(db, db_path.c_str());
 
	LOG4CXX_INFO(logger,  m_username << ": Spawning new Skype instance dbpath=" << db);
 
	gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0};
 

	
 
	int fd;
 
	g_spawn_async_with_pipes(NULL,
 
		argv,
 
		NULL /*envp*/,
 
		G_SPAWN_SEARCH_PATH,
 
		NULL /*child_setup*/,
 
		NULL /*user_data*/,
 
		&m_pid /*child_pid*/,
 
		&fd,
 
		NULL,
 
		&fd_output,
 
		NULL /*error*/);
 
	std::string login_data = std::string(m_username + " " + m_password + "\n");
 
	LOG4CXX_INFO(logger,  m_username << ": Login data=" << login_data);
 
	write(fd, login_data.c_str(), login_data.size());
 
	close(fd);
 

	
 
	fcntl (fd_output, F_SETFL, O_NONBLOCK);
 

	
 
	free(db);
 

	
 
	//Initialise threading
 
	dbus_threads_init_default();
 

	
 
	if (m_connection == NULL)
 
	{
 
		LOG4CXX_INFO(logger, "Creating DBus connection.");
 
		GError *error = NULL;
 
		m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
 
		if (m_connection == NULL && error != NULL)
 
		{
 
			LOG4CXX_INFO(logger,  m_username << ": DBUS Error: " << error->message);
 
			g_error_free(error);
 
			return;
 
		}
 
	}
 

	
 
	m_timer = g_timeout_add_seconds(1, create_dbus_proxy, this);
 
}
 

	
 
bool Skype::loadSkypeBuddies() {
 
//	std::string re = "CONNSTATUS OFFLINE";
 
//	while (re == "CONNSTATUS OFFLINE" || re.empty()) {
 
//		sleep(1);
 

	
 
	gchar buffer[1024];
 
	int bytes_read = read(fd_output, buffer, 1023);
 
	if (bytes_read > 0) {
 
		buffer[bytes_read] = 0;
 
		np->handleDisconnected(m_user, 0, buffer);
 
		close(fd_output);
 
		logout();
 
		return FALSE;
 
	}
 

	
 
	std::string re = send_command("NAME Spectrum");
 
	if (m_counter++ > 15) {
 
		np->handleDisconnected(m_user, 0, "");
 
		close(fd_output);
 
		logout();
 
		return FALSE;
 
	}
 

	
 
	if (re.empty() || re == "CONNSTATUS OFFLINE") {
 
		return TRUE;
 
	}
 

	
 
	close(fd_output);
 

	
 
	if (send_command("PROTOCOL 7") != "PROTOCOL 7") {
 
		np->handleDisconnected(m_user, 0, "Skype is not ready");
 
		logout();
 
		return FALSE;
 
	}
 

	
 
	np->handleConnected(m_user);
 

	
 
	std::map<std::string, std::string> group_map;
 
	std::string groups = send_command("SEARCH GROUPS CUSTOM");
 
	groups = groups.substr(groups.find(' ') + 1);
 
	std::vector<std::string> grps;
 
	boost::split(grps, groups, boost::is_any_of(","));
 
	BOOST_FOREACH(std::string grp, grps) {
 
		std::vector<std::string> data;
 
		std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME");
 
		boost::split(data, name, boost::is_any_of(" "));
 
		name = name.substr(name.find("DISPLAYNAME") + 12);
 

	
 
		std::string users = send_command("GET GROUP " + data[1] + " USERS");
 
		users = name.substr(name.find("USERS") + 6);
 
		boost::split(data, users, boost::is_any_of(","));
 
		BOOST_FOREACH(std::string u, data) {
 
			group_map[u] = grp;
 
		}
 
	}
 

	
 
	std::string friends = send_command("GET AUTH_CONTACTS_PROFILES");
 

	
 
	char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0);
 
	if (full_friends_list && full_friends_list[0])
 
	{
 
		//in the format of: username;full name;phone;office phone;mobile phone;
 
		//                  online status;friendly name;voicemail;mood
 
		// (comma-seperated lines, usernames can have comma's)
 

	
 
		for (int i=0; full_friends_list[i] && full_friends_list[i+1] && *full_friends_list[i] != '\0'; i+=8)
 
		{
 
			std::string buddy = full_friends_list[i];
 

	
 
			if (buddy[0] == ',') {
 
				buddy.erase(buddy.begin());
 
			}
 

	
 
			if (buddy.rfind(",") != std::string::npos) {
 
				buddy = buddy.substr(buddy.rfind(","));
 
			}
 

	
 
			if (buddy[0] == ',') {
 
				buddy.erase(buddy.begin());
 
			}
 

	
 
			LOG4CXX_INFO(logger, "Got buddy " << buddy);
 
			std::string st = full_friends_list[i + 5];
 

	
 
			pbnetwork::StatusType status = getStatus(st);
 

	
 
			std::string alias = full_friends_list[i + 6];
 

	
 
			std::string mood_text = "";
 
			if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') {
 
				mood_text = full_friends_list[i + 8];
 
			}
 

	
 
			std::vector<std::string> groups;
 
			if (group_map.find(buddy) != group_map.end()) {
 
				groups.push_back(group_map[buddy]);
 
			}
 
			np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text);
 
		}
 
	}
 
	g_strfreev(full_friends_list);
 

	
 
	send_command("SET AUTOAWAY OFF");
 
	send_command("SET USERSTATUS ONLINE");
 
	return FALSE;
 
}
 

	
 
void Skype::logout() {
 
	if (m_pid != 0) {
 
		send_command("SET USERSTATUS INVISIBLE");
 
		send_command("SET USERSTATUS OFFLINE");
 
		sleep(2);
 
		g_object_unref(m_proxy);
 
		LOG4CXX_INFO(logger,  m_username << ": Killing Skype instance");
 
		kill((int) m_pid, SIGTERM);
 
		m_pid = 0;
 
	}
 
}
 

	
 
std::string Skype::send_command(const std::string &message) {
 
	GError *error = NULL;
 
	gchar *str = NULL;
 
// 			int message_num;
 
// 			gchar error_return[30];
 

	
 
	if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID,
 
						G_TYPE_STRING, &str, G_TYPE_INVALID))
 
	{
 
			if (error && error->message)
 
			{
 
			LOG4CXX_INFO(logger,  m_username << ": DBUS Error: " << error->message);
 
			g_error_free(error);
 
		} else {
 
			LOG4CXX_INFO(logger,  m_username << ": DBUS no response");
 
		}
 

	
 
	}
 
	if (str != NULL)
 
	{
 
		LOG4CXX_INFO(logger,  m_username << ": DBUS:" << str);
 
	}
 
	return str ? std::string(str) : std::string();
 
}
 

	
 
static void handle_skype_message(std::string &message, Skype *sk) {
 
	std::vector<std::string> cmd;
 
	boost::split(cmd, message, boost::is_any_of(" "));
 

	
 
	if (cmd[0] == "USER") {
 
		if (cmd[1] == sk->getUsername()) {
 
			return;
 
		}
 

	
 
		if (cmd[2] == "ONLINESTATUS") {
 
			if (cmd[3] == "SKYPEOUT" || cmd[3] == "UNKNOWN") {
 
				return;
 
			}
 
			else {
 
				pbnetwork::StatusType status = getStatus(cmd[3]);
 
				std::string mood_text = sk->send_command("GET USER " + cmd[1] + " MOOD_TEXT");
 
				mood_text = mood_text.substr(mood_text.find("MOOD_TEXT") + 10);
 

	
 
				std::string alias = sk->send_command("GET USER " + cmd[1] + " FULLNAME");
 
				alias = alias.substr(alias.find("FULLNAME") + 9);
 

	
 
				std::vector<std::string> groups;
 
				np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text);
 
			}
 
		}
 
		else if (cmd[2] == "MOOD_TEXT") {
 
			std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
 
			st = st.substr(st.find("ONLINESTATUS") + 13);
 
			pbnetwork::StatusType status = getStatus(st);
 

	
 
			std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10);
 

	
 
			std::vector<std::string> groups;
 
			np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
 
		}
 
		else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") {
 
			std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
 
			st = st.substr(st.find("ONLINESTATUS") + 13);
 
			pbnetwork::StatusType status = getStatus(st);
 

	
 
			std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10);
 

	
 
			std::vector<std::string> groups;
 
			np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text);
 
		}
 
		else if (cmd[2] == "FULLNAME") {
 
			std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS");
 
			st = st.substr(st.find("ONLINESTATUS") + 13);
 
			pbnetwork::StatusType status = getStatus(st);
 

	
 
			std::string mood_text = sk->send_command("GET USER " + cmd[1] + " MOOD_TEXT");
 
			mood_text = mood_text.substr(mood_text.find("MOOD_TEXT") + 10);
 

	
 
			std::string alias = message.substr(message.find("FULLNAME") + 9);
 

	
 
			std::vector<std::string> groups;
 
			np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text);
 
		}
 
	}
 
	else if (cmd[0] == "CHATMESSAGE") {
 
		if (cmd[3] == "RECEIVED") {
 
			std::string body = sk->send_command("GET CHATMESSAGE " + cmd[1] + " BODY");
 
			body = body.substr(body.find("BODY") + 5);
 

	
 
			std::string chatname = sk->send_command("GET CHATMESSAGE " + cmd[1] + " CHATNAME");
 
			size_t start = chatname.find("$") + 1;
 
			size_t len = chatname.find(";") - start;
 
			std::string from = chatname.substr(start, len);
 

	
 
			std::string from_handle = sk->send_command("GET CHATMESSAGE " + cmd[1] + " FROM_HANDLE");
 
			from_handle = from_handle.substr(from_handle.find("FROM_HANDLE") + 12);
 

	
 
// 			if (from_handle != sk->getUsername()) {
 
				from = from_handle;
 
// 			}
 
			if (from_handle == sk->getUsername())
 
				return;
 

	
 
			np->handleMessage(sk->getUser(), from, body);
 
		}
 
	}
 
}
 

	
 
DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data) {
 
	DBusMessageIter iterator;
 
	gchar *message_temp;
 
	DBusMessage *temp_message;
 
	
 
	temp_message = dbus_message_ref(message);
 
	dbus_message_iter_init(temp_message, &iterator);
 
	if (dbus_message_iter_get_arg_type(&iterator) != DBUS_TYPE_STRING)
 
	{
 
		dbus_message_unref(message);
 
		return (DBusHandlerResult) FALSE;
 
	}
 
	
 
	do {
 
		dbus_message_iter_get_basic(&iterator, &message_temp);
 
		std::string m(message_temp);
 
		LOG4CXX_INFO(logger,"DBUS message: " << m);
 
		handle_skype_message(m, (Skype *) user_data);
 
	} while(dbus_message_iter_has_next(&iterator) && dbus_message_iter_next(&iterator));
 
	
 
	dbus_message_unref(message);
 
	
 
	return DBUS_HANDLER_RESULT_HANDLED;
 
}
 

	
 
static void spectrum_sigchld_handler(int sig)
 
{
 
	int status;
 
	pid_t pid;
 

	
 
	do {
 
		pid = waitpid(-1, &status, WNOHANG);
 
	} while (pid != 0 && pid != (pid_t)-1);
 

	
 
	if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
 
		char errmsg[BUFSIZ];
 
		snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
 
		perror(errmsg);
 
	}
 
}
 

	
 
static int create_socket(char *host, int portno) {
 
	struct sockaddr_in serv_addr;
 
	
 
	int m_sock = socket(AF_INET, SOCK_STREAM, 0);
 
	memset((char *) &serv_addr, 0, sizeof(serv_addr));
 
	serv_addr.sin_family = AF_INET;
 
	serv_addr.sin_port = htons(portno);
 

	
 
	hostent *hos;  // Resolve name
 
	if ((hos = gethostbyname(host)) == NULL) {
 
		// strerror() will not work for gethostbyname() and hstrerror() 
 
		// is supposedly obsolete
 
		exit(1);
 
	}
 
	serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]);
 

	
 
	if (connect(m_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
 
		close(m_sock);
 
		m_sock = 0;
 
	}
 

	
 
	int flags = fcntl(m_sock, F_GETFL);
 
	flags |= O_NONBLOCK;
 
	fcntl(m_sock, F_SETFL, flags);
 
	return m_sock;
 
}
 

	
 

	
 
static gboolean transportDataReceived(GIOChannel *source, GIOCondition condition, gpointer data) {
 
	char buffer[65535];
 
	char *ptr = buffer;
 
	ssize_t n = read(m_sock, ptr, sizeof(buffer));
 
	if (n <= 0) {
 
		LOG4CXX_INFO(logger, "Diconnecting from spectrum2 server");
 
		exit(errno);
 
	}
 
	std::string d = std::string(buffer, n);
 
	np->handleDataRead(d);
 
	return TRUE;
 
}
 

	
 
static void io_destroy(gpointer data) {
 
	exit(1);
 
}
 

	
 
static void log_glib_error(const gchar *string) {
 
	LOG4CXX_ERROR(logger, "GLIB ERROR:" << string);
 
}
 

	
 
int main(int argc, char **argv) {
 
	GError *error = NULL;
 
	GOptionContext *context;
 
	context = g_option_context_new("config_file_name or profile name");
 
	g_option_context_add_main_entries(context, options_entries, "");
 
	if (!g_option_context_parse (context, &argc, &argv, &error)) {
 
		std::cout << "option parsing failed: " << error->message << "\n";
 
		return -1;
 
	}
 

	
 
	if (ver) {
 
// 		std::cout << VERSION << "\n";
 
		std::cout << "verze\n";
 
		g_option_context_free(context);
 
		return 0;
 
	}
 

	
 
	if (argc != 2) {
 
#ifdef WIN32
 
		std::cout << "Usage: spectrum.exe <configuration_file.cfg>\n";
 
#else
 

	
 
#if GLIB_CHECK_VERSION(2,14,0)
 
	std::cout << g_option_context_get_help(context, FALSE, NULL);
 
#else
 
	std::cout << "Usage: spectrum <configuration_file.cfg>\n";
 
	std::cout << "See \"man spectrum\" for more info.\n";
 
#endif
 
		
 
#endif
 
	}
 
	else {
 
#ifndef WIN32
 
		signal(SIGPIPE, SIG_IGN);
 

	
 
		if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
 
			std::cout << "SIGCHLD handler can't be set\n";
 
			g_option_context_free(context);
 
			return -1;
 
		}
 
// 
 
// 		if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) {
 
// 			std::cout << "SIGINT handler can't be set\n";
 
// 			g_option_context_free(context);
 
// 			return -1;
 
// 		}
 
// 
 
// 		if (signal(SIGTERM, spectrum_sigterm_handler) == SIG_ERR) {
 
// 			std::cout << "SIGTERM handler can't be set\n";
 
// 			g_option_context_free(context);
 
// 			return -1;
 
// 		}
 
// 
 
// 		struct sigaction sa;
 
// 		memset(&sa, 0, sizeof(sa)); 
 
// 		sa.sa_handler = spectrum_sighup_handler;
 
// 		if (sigaction(SIGHUP, &sa, NULL)) {
 
// 			std::cout << "SIGHUP handler can't be set\n";
 
// 			g_option_context_free(context);
 
// 			return -1;
 
//		}
 
#endif
 
		Config config;
 
		if (!config.load(argv[1])) {
 
			std::cout << "Can't open " << argv[1] << " configuration file.\n";
 
			return 1;
 
		}
 

	
 
		if (CONFIG_STRING(&config, "logging.backend_config").empty()) {
 
			LoggerPtr root = log4cxx::Logger::getRootLogger();
 
			root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
 
		}
 
		else {
 
			log4cxx::helpers::Properties p;
 
			log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config"));
 

	
 
			p.load(istream);
 
			p.setProperty("pid", boost::lexical_cast<std::string>(getpid()));
 
			log4cxx::PropertyConfigurator::configure(p);
 
		}
 

	
 
// 		initPurple(config);
 

	
 
		g_type_init();
 

	
 
		m_sock = create_socket(host, port);
 

	
 
		g_set_printerr_handler(log_glib_error);
 

	
 
	GIOChannel *channel;
 
	GIOCondition cond = (GIOCondition) G_IO_IN;
 
	channel = g_io_channel_unix_new(m_sock);
 
	g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy);
 

	
 
		np = new SpectrumNetworkPlugin(&config, host, port);
 

	
 
		GMainLoop *m_loop;
 
		m_loop = g_main_loop_new(NULL, FALSE);
 

	
 
		if (m_loop) {
 
			g_main_loop_run(m_loop);
 
		}
 
	}
 

	
 
	g_option_context_free(context);
 
}
backends/smstools3/CMakeLists.txt
Show inline comments
 
new file 100644
 
cmake_minimum_required(VERSION 2.6)
 
 
FILE(GLOB SRC *.c *.cpp)
 
 
ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC})
 
 
target_link_libraries(spectrum2_smstools3_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
 
 
INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin)
 
backends/smstools3/main.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com
 
 *
 
 * This example is free, and not covered by LGPL license. There is no
 
 * restriction applied to their modification, redistribution, using and so on.
 
 * You can study them, modify them, use them in your own program - either
 
 * completely or partially. By using it you may give me some credits in your
 
 * program, but you don't have to.
 
 */
 

	
 
#include "transport/config.h"
 
#include "transport/networkplugin.h"
 
#include "transport/sqlite3backend.h"
 
#include "transport/mysqlbackend.h"
 
#include "transport/pqxxbackend.h"
 
#include "transport/storagebackend.h"
 
#include "Swiften/Swiften.h"
 
#include <boost/filesystem.hpp>
 
#include "unistd.h"
 
#include "signal.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
#include <fstream>
 
#include <streambuf>
 

	
 
Swift::SimpleEventLoop *loop_;
 

	
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 
#include <boost/filesystem.hpp>
 
#include <boost/algorithm/string.hpp>
 

	
 
using namespace boost::filesystem;
 

	
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
using namespace log4cxx;
 

	
 
static LoggerPtr logger = log4cxx::Logger::getLogger("SMSNetworkPlugin");
 

	
 
#define INTERNAL_USER "/sms@backend@internal@user"
 

	
 
class SMSNetworkPlugin;
 
SMSNetworkPlugin * np = NULL;
 
StorageBackend *storageBackend;
 

	
 
class SMSNetworkPlugin : public NetworkPlugin {
 
	public:
 
		Swift::BoostNetworkFactories *m_factories;
 
		Swift::BoostIOServiceThread m_boostIOServiceThread;
 
		boost::shared_ptr<Swift::Connection> m_conn;
 
		Swift::Timer::ref m_timer;
 
		int m_internalUser;
 

	
 
		SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() {
 
			this->config = config;
 
			m_factories = new Swift::BoostNetworkFactories(loop);
 
			m_conn = m_factories->getConnectionFactory()->createConnection();
 
			m_conn->onDataRead.connect(boost::bind(&SMSNetworkPlugin::_handleDataRead, this, _1));
 
			m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port));
 
// 			m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1));
 
// 			m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this));
 

	
 
			LOG4CXX_INFO(logger, "Starting the plugin.");
 

	
 
			m_timer = m_factories->getTimerFactory()->createTimer(5000);
 
			m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this));
 
			m_timer->start();
 

	
 
			// We're reusing our database model here. Buddies of user with JID INTERNAL_USER are there
 
			// to match received GSM messages from number N with the XMPP users who sent message to number N.
 
			// BuddyName = GSM number
 
			// Alias = XMPP user JID to which the messages from this number is sent to.
 
			// TODO: This should be per Modem!!!
 
			UserInfo info;
 
			info.jid = INTERNAL_USER;
 
			info.password = "";
 
			storageBackend->setUser(info);
 
			storageBackend->getUser(INTERNAL_USER, info);
 
			m_internalUser = info.id;
 
		}
 

	
 

	
 
		void handleSMS(const std::string &sms) {
 
			LOG4CXX_INFO(logger, "Handling SMS " << sms << ".")
 
			std::ifstream t(sms.c_str());
 
			std::string str;
 

	
 
			t.seekg(0, std::ios::end);
 
			str.reserve(t.tellg());
 
			t.seekg(0, std::ios::beg);
 

	
 
			str.assign((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
 

	
 
			std::string from = "";
 
			std::string msg = "";
 
			while(str.find("\n") != std::string::npos) {
 
				std::string line = str.substr(0, str.find("\n"));
 
				if (line.find("From: ") == 0) {
 
					from = line.substr(strlen("From: "));
 
				}
 
				else if (line.empty()) {
 
					msg = str.substr(1);
 
					break;
 
				}
 
				str = str.substr(str.find("\n") + 1);
 
			}
 

	
 
			std::list<BuddyInfo> roster;
 
			storageBackend->getBuddies(m_internalUser, roster);
 

	
 
			std::string to;
 
			BOOST_FOREACH(BuddyInfo &b, roster) {
 
				if (b.legacyName == from) {
 
					to = b.alias;
 
				}
 
			}
 

	
 
			if (to.empty()) {
 
				LOG4CXX_WARN(logger, "Received SMS from " << from << ", but this number is not associated with any XMPP user.");
 
			}
 

	
 
			LOG4CXX_INFO(logger, "Forwarding SMS from " << from << " to " << to << ".");
 
			handleMessage(to, from, msg);
 
		}
 

	
 
		void handleSMSDir() {
 
			std::string dir = "/var/spool/sms/incoming/";
 
			if (config->getUnregistered().find("backend.incoming_dir") != config->getUnregistered().end()) {
 
				dir = config->getUnregistered().find("backend.incoming_dir")->second;
 
			}
 
			LOG4CXX_INFO(logger, "Checking directory " << dir << " for incoming SMS.");
 

	
 
			path p(dir);
 
			directory_iterator end_itr;
 
			for (directory_iterator itr(p); itr != end_itr; ++itr) {
 

	
 
				try {
 
					if (is_regular(itr->path())) {
 
						handleSMS(itr->path().string());
 
						remove(itr->path());
 
					}
 
				}
 
				catch (const filesystem_error& ex) {
 
					LOG4CXX_ERROR(logger, "Error when removing the SMS: " << ex.what() << ".");
 
				}
 
			}
 
			m_timer->start();
 
		}
 

	
 
		void sendSMS(const std::string &to, const std::string &msg) {
 
			// TODO: Probably 
 
			std::string data = "To: " + to + "\n";
 
			data += "\n";
 
			data += msg;
 

	
 
			// generate random string here...
 
			std::string bucket = "abcdefghijklmnopqrstuvwxyz";
 
			std::string uuid;
 
			for (int i = 0; i < 10; i++) {
 
				uuid += bucket[rand() % bucket.size()];
 
			}
 
			std::ofstream myfile;
 
			myfile.open (std::string("/var/spool/sms/outgoing/spectrum." + uuid).c_str());
 
			myfile << data;
 
			myfile.close();
 
		}
 

	
 
		void sendData(const std::string &string) {
 
			m_conn->write(Swift::createSafeByteArray(string));
 
		}
 

	
 
		void _handleDataRead(boost::shared_ptr<Swift::SafeByteArray> data) {
 
			std::string d(data->begin(), data->end());
 
			handleDataRead(d);
 
		}
 

	
 
		void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
			UserInfo info;
 
			if (!storageBackend->getUser(user, info)) {
 
				handleDisconnected(user, 0, "Not registered user.");
 
				return;
 
			}
 
			std::list<BuddyInfo> roster;
 
			storageBackend->getBuddies(info.id, roster);
 

	
 
			// Send available presence to every number in the roster.
 
			BOOST_FOREACH(BuddyInfo &b, roster) {
 
				handleBuddyChanged(user, b.legacyName, b.alias, b.groups, pbnetwork::STATUS_ONLINE);
 
			}
 

	
 
			np->handleConnected(user);
 
		}
 

	
 
		void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
		}
 

	
 
		void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") {
 
			// Remove trailing +, because smstools doesn't use it in "From: " field for received messages.
 
			std::string n = legacyName;
 
			if (n.find("+") == 0) {
 
				n = n.substr(1);
 
			}
 

	
 
			// Create GSM Number - XMPP user pair to match the potential response and send it to the proper JID.
 
			BuddyInfo info;
 
			info.legacyName = n;
 
			info.alias = user;
 
			info.id = -1;
 
			info.subscription = "both";
 
			info.flags = 0;
 
			storageBackend->addBuddy(m_internalUser, info);
 

	
 
			LOG4CXX_INFO(logger, "Sending SMS from " << user << " to " << n << ".");
 
			sendSMS(n, message);
 
		}
 

	
 
		void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) {
 
		}
 

	
 
		void handleLeaveRoomRequest(const std::string &user, const std::string &room) {
 
		}
 

	
 
		void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
 
			LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << ".");
 
			handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE);
 
		}
 

	
 
		void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
 

	
 
		}
 

	
 

	
 
	private:
 
		
 
		Config *config;
 
};
 

	
 
static void spectrum_sigchld_handler(int sig)
 
{
 
	int status;
 
	pid_t pid;
 

	
 
	do {
 
		pid = waitpid(-1, &status, WNOHANG);
 
	} while (pid != 0 && pid != (pid_t)-1);
 

	
 
	if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
 
		char errmsg[BUFSIZ];
 
		snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
 
		perror(errmsg);
 
	}
 
}
 

	
 

	
 
int main (int argc, char* argv[]) {
 
	std::string host;
 
	int port;
 

	
 
	if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
 
		std::cout << "SIGCHLD handler can't be set\n";
 
		return -1;
 
	}
 

	
 
	boost::program_options::options_description desc("Usage: spectrum [OPTIONS] <config_file.cfg>\nAllowed options");
 
	desc.add_options()
 
		("host,h", value<std::string>(&host), "host")
 
		("port,p", value<int>(&port), "port")
 
		;
 
	try
 
	{
 
		boost::program_options::variables_map vm;
 
		boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
 
		boost::program_options::notify(vm);
 
	}
 
	catch (std::runtime_error& e)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 
	catch (...)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 

	
 

	
 
	if (argc < 5) {
 
		return 1;
 
	}
 

	
 
// 	QStringList channels;
 
// 	for (int i = 3; i < argc; ++i)
 
// 	{
 
// 		channels.append(argv[i]);
 
// 	}
 
// 
 
// 	MyIrcSession session;
 
// 	session.setNick(argv[2]);
 
// 	session.setAutoJoinChannels(channels);
 
// 	session.connectToServer(argv[1], 6667);
 

	
 
	Config config;
 
	if (!config.load(argv[5])) {
 
		std::cerr << "Can't open " << argv[1] << " configuration file.\n";
 
		return 1;
 
	}
 

	
 
	if (CONFIG_STRING(&config, "logging.backend_config").empty()) {
 
		LoggerPtr root = log4cxx::Logger::getRootLogger();
 
#ifndef _MSC_VER
 
		root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
 
#else
 
		root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n")));
 
#endif
 
	}
 
	else {
 
		log4cxx::helpers::Properties p;
 
		log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config"));
 
		p.load(istream);
 
		LogString pid, jid;
 
		log4cxx::helpers::Transcoder::decode(boost::lexical_cast<std::string>(getpid()), pid);
 
		log4cxx::helpers::Transcoder::decode(CONFIG_STRING(&config, "service.jid"), jid);
 
#ifdef _MSC_VER
 
		p.setProperty(L"pid", pid);
 
		p.setProperty(L"jid", jid);
 
#else
 
		p.setProperty("pid", pid);
 
		p.setProperty("jid", jid);
 
#endif
 
		log4cxx::PropertyConfigurator::configure(p);
 
	}
 

	
 
#ifdef WITH_SQLITE
 
	if (CONFIG_STRING(&config, "database.type") == "sqlite3") {
 
		storageBackend = new SQLite3Backend(&config);
 
		if (!storageBackend->connect()) {
 
			std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
 
			return -1;
 
		}
 
	}
 
#else
 
	if (CONFIG_STRING(&config, "database.type") == "sqlite3") {
 
		std::cerr << "Spectrum2 is not compiled with mysql backend.\n";
 
		return -2;
 
	}
 
#endif
 

	
 
#ifdef WITH_MYSQL
 
	if (CONFIG_STRING(&config, "database.type") == "mysql") {
 
		storageBackend = new MySQLBackend(&config);
 
		if (!storageBackend->connect()) {
 
			std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
 
			return -1;
 
		}
 
	}
 
#else
 
	if (CONFIG_STRING(&config, "database.type") == "mysql") {
 
		std::cerr << "Spectrum2 is not compiled with mysql backend.\n";
 
		return -2;
 
	}
 
#endif
 

	
 
#ifdef WITH_PQXX
 
	if (CONFIG_STRING(&config, "database.type") == "pqxx") {
 
		storageBackend = new PQXXBackend(&config);
 
		if (!storageBackend->connect()) {
 
			std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
 
			return -1;
 
		}
 
	}
 
#else
 
	if (CONFIG_STRING(&config, "database.type") == "pqxx") {
 
		std::cerr << "Spectrum2 is not compiled with pqxx backend.\n";
 
		return -2;
 
	}
 
#endif
 

	
 
	if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3"
 
		&& CONFIG_STRING(&config, "database.type") != "pqxx" && CONFIG_STRING(&config, "database.type") != "none") {
 
		std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n";
 
		return -2;
 
	}
 

	
 
	Swift::SimpleEventLoop eventLoop;
 
	loop_ = &eventLoop;
 
	np = new SMSNetworkPlugin(&config, &eventLoop, host, port);
 
	loop_->run();
 

	
 
	return 0;
 
}
backends/template/CMakeLists.txt
Show inline comments
 
new file 100644
 
cmake_minimum_required(VERSION 2.6)
 
 
FILE(GLOB SRC *.c *.cpp)
 
 
ADD_EXECUTABLE(spectrum2_template_backend ${SRC})
 
 
if (NOT WIN32)
 
target_link_libraries(spectrum2_template_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
 
else()
 
target_link_libraries(spectrum2_template_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
 
endif()
 
 
#INSTALL(TARGETS spectrum2_template_backend RUNTIME DESTINATION bin)
 
backends/template/README
Show inline comments
 
new file 100644
 
This is just template for creating new generic spectrum2 backends. It does not do anything!
 
\ No newline at end of file
backends/template/main.cpp
Show inline comments
 
new file 100644
 
// Transport includes
 
#include "transport/config.h"
 
#include "transport/networkplugin.h"
 

	
 
// Swiften
 
#include "Swiften/Swiften.h"
 

	
 
#ifndef _MSC_VER
 
// for signal handler
 
#include "unistd.h"
 
#include "signal.h"
 
#include "sys/wait.h"
 
#include "sys/signal.h"
 
#endif
 
// Log4cxx
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
#include "log4cxx/helpers/properties.h"
 
#include "log4cxx/helpers/fileinputstream.h"
 
#include "log4cxx/helpers/transcoder.h"
 

	
 
// Boost
 
#include <boost/algorithm/string.hpp>
 
using namespace boost::filesystem;
 
using namespace boost::program_options;
 
using namespace Transport;
 

	
 
// log4cxx main logger
 
using namespace log4cxx;
 
static LoggerPtr logger = log4cxx::Logger::getLogger("Backend Template");
 

	
 
// eventloop
 
Swift::SimpleEventLoop *loop_;
 

	
 
// Plugin
 
class TemplatePlugin;
 
TemplatePlugin * np = NULL;
 

	
 
class TemplatePlugin : public NetworkPlugin {
 
	public:
 
		Swift::BoostNetworkFactories *m_factories;
 
		Swift::BoostIOServiceThread m_boostIOServiceThread;
 
		boost::shared_ptr<Swift::Connection> m_conn;
 

	
 
		TemplatePlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() {
 
			this->config = config;
 
			m_factories = new Swift::BoostNetworkFactories(loop);
 
			m_conn = m_factories->getConnectionFactory()->createConnection();
 
			m_conn->onDataRead.connect(boost::bind(&TemplatePlugin::_handleDataRead, this, _1));
 
			m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port));
 

	
 
			LOG4CXX_INFO(logger, "Starting the plugin.");
 
		}
 

	
 
		// NetworkPlugin uses this method to send the data to networkplugin server
 
		void sendData(const std::string &string) {
 
			m_conn->write(Swift::createSafeByteArray(string));
 
		}
 

	
 
		// This method has to call handleDataRead with all received data from network plugin server
 
		void _handleDataRead(boost::shared_ptr<Swift::SafeByteArray> data) {
 
			std::string d(data->begin(), data->end());
 
			handleDataRead(d);
 
		}
 

	
 
		void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
 
			handleConnected(user);
 
		}
 

	
 
		void handleLogoutRequest(const std::string &user, const std::string &legacyName) {
 
		}
 

	
 
		void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") {
 
			LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << ".");
 
		}
 

	
 
		void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups) {
 
			LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << ".");
 
			handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE);
 
		}
 

	
 
		void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
 

	
 
		}
 

	
 
	private:
 
		Config *config;
 
};
 

	
 
#ifndef _MSC_VER
 

	
 
static void spectrum_sigchld_handler(int sig)
 
{
 
	int status;
 
	pid_t pid;
 

	
 
	do {
 
		pid = waitpid(-1, &status, WNOHANG);
 
	} while (pid != 0 && pid != (pid_t)-1);
 

	
 
	if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
 
		char errmsg[BUFSIZ];
 
		snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
 
		perror(errmsg);
 
	}
 
}
 
#endif
 

	
 
int main (int argc, char* argv[]) {
 
	std::string host;
 
	int port;
 

	
 
#ifndef _MSC_VER
 
	if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) {
 
		std::cout << "SIGCHLD handler can't be set\n";
 
		return -1;
 
	}
 
#endif
 
	boost::program_options::options_description desc("Usage: spectrum [OPTIONS] <config_file.cfg>\nAllowed options");
 
	desc.add_options()
 
		("host,h", value<std::string>(&host), "host")
 
		("port,p", value<int>(&port), "port")
 
		;
 
	try
 
	{
 
		boost::program_options::variables_map vm;
 
		boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
 
		boost::program_options::notify(vm);
 
	}
 
	catch (std::runtime_error& e)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 
	catch (...)
 
	{
 
		std::cout << desc << "\n";
 
		exit(1);
 
	}
 

	
 

	
 
	if (argc < 5) {
 
		return 1;
 
	}
 

	
 
	Config config;
 
	if (!config.load(argv[5])) {
 
		std::cerr << "Can't open " << argv[1] << " configuration file.\n";
 
		return 1;
 
	}
 

	
 
	if (CONFIG_STRING(&config, "logging.backend_config").empty()) {
 
		LoggerPtr root = log4cxx::Logger::getRootLogger();
 
#ifndef _MSC_VER
 
		root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n")));
 
#else
 
		root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n")));
 
#endif
 
	}
 
	else {
 
		log4cxx::helpers::Properties p;
 
		log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config"));
 
		p.load(istream);
 
		LogString pid, jid;
 
		log4cxx::helpers::Transcoder::decode(boost::lexical_cast<std::string>(getpid()), pid);
 
		log4cxx::helpers::Transcoder::decode(CONFIG_STRING(&config, "service.jid"), jid);
 
#ifdef _MSC_VER
 
		p.setProperty(L"pid", pid);
 
		p.setProperty(L"jid", jid);
 
#else
 
		p.setProperty("pid", pid);
 
		p.setProperty("jid", jid);
 
#endif
 
		log4cxx::PropertyConfigurator::configure(p);
 
	}
 

	
 
	Swift::SimpleEventLoop eventLoop;
 
	loop_ = &eventLoop;
 
	np = new TemplatePlugin(&config, &eventLoop, host, port);
 
	loop_->run();
 

	
 
	return 0;
 
}
cmake_modules/dbusConfig.cmake
Show inline comments
 
new file 100644
 
# - Try to find LIBDBUS GLIB Bindings
 
# Find LIBDBUSGLIB headers, libraries and the answer to all questions.
 
#
 
#  LIBDBUSGLIB_FOUND               True if libdbus-glib got found
 
#  LIBDBUSGLIB_INCLUDE_DIRS        Location of libdbus-glib headers 
 
#  LIBDBUSGLIB_LIBRARIES           List of libraries to use libdbus-glib 
 
#
 
# Copyright (c) 2008 Bjoern Ricks <bjoern.ricks@googlemail.com>
 
#
 
#  Redistribution and use is allowed according to the terms of the New
 
#  BSD license.
 
#  For details see the accompanying COPYING-CMAKE-SCRIPTS file.
 
#
 

	
 
INCLUDE( FindPkgConfig )
 

	
 
IF ( LibDbusGlib_FIND_REQUIRED )
 
	SET( _pkgconfig_REQUIRED "REQUIRED" )
 
ELSE( LibDbusGlib_FIND_REQUIRED )
 
	SET( _pkgconfig_REQUIRED "" )	
 
ENDIF ( LibDbusGlib_FIND_REQUIRED )
 

	
 
IF ( LIBDBUSGLIB_MIN_VERSION )
 
	PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1>=${LIBDBUSGLIB_MIN_VERSION} )
 
ELSE ( LIBDBUSGLIB_MIN_VERSION )
 
	PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1 )
 
ENDIF ( LIBDBUSGLIB_MIN_VERSION )
 

	
 

	
 
IF( NOT LIBDBUSGLIB_FOUND AND NOT PKG_CONFIG_FOUND )
 
	FIND_PATH( LIBDBUSGLIB_INCLUDE_DIRS dbus/dbus-glib.h PATH_SUFFIXES dbus-1.0 dbus )
 
	FIND_LIBRARY( LIBDBUSGLIB_LIBRARIES dbus-glib dbus-glib-1)
 

	
 
	# Report results
 
	IF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS )	
 
		SET( LIBDBUSGLIB_FOUND 1 )
 
		IF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
 
			MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" )
 
		ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
 
	ELSE ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS )	
 
		IF ( LIBDBUSGLIB_FIND_REQUIRED )
 
			MESSAGE( SEND_ERROR "Could NOT find libdbus-glib" )
 
		ELSE ( LIBDBUSGLIB_FIND_REQUIRED )
 
			IF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
 
				MESSAGE( STATUS "Could NOT find libdbus-glib" )	
 
			ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY )
 
		ENDIF ( LIBDBUSGLIB_FIND_REQUIRED )
 
	ENDIF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS )
 
else()
 
	MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" )
 
ENDIF()
 

	
 
MARK_AS_ADVANCED( LIBDBUSGLIB_LIBRARIES LIBDBUSGLIB_INCLUDE_DIRS )
 
\ No newline at end of file
cmake_modules/log4cxxConfig.cmake
Show inline comments
 
@@ -2,7 +2,7 @@
 
# LOG4CXX_INCLUDE_DIR - the liblog4cxx include directory
 
# LOG4CXX_LIBRARIES - liblog4cxx library
 

	
 
FIND_PATH(LOG4CXX_INCLUDE_DIR logger.h PATHS /include/log4cxx /usr/include/log4cxx /usr/local/include/log4cxx )
 
FIND_PATH(LOG4CXX_INCLUDE_DIR log4cxx/logger.h PATHS /include /usr/include /usr/local/include )
 
FIND_LIBRARY(LOG4CXX_LIBRARIES NAMES log4cxx log4cxxd PATHS /lib /usr/lib /usr/local/lib )
 

	
 
IF(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARIES)
include/Swiften/Elements/GatewayPayload.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Elements/GatewayPayload.h>
 

	
 
namespace Swift {
 

	
 
GatewayPayload::GatewayPayload(const JID &jid, const std::string &desc, const std::string &prompt) :
 
	jid(jid), desc(desc), prompt(prompt) {
 
		
 
	}
 

	
 
}
include/Swiften/Elements/GatewayPayload.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 

	
 
#include <string>
 
#include <Swiften/Elements/Payload.h>
 
#include <Swiften/JID/JID.h>
 

	
 
namespace Swift {
 
	class GatewayPayload : public Payload {
 
		public:
 
			GatewayPayload(const JID &jid = JID(), const std::string &desc = "", const std::string &prompt = "");
 

	
 
			void setJID(const JID &jid) {
 
				this->jid = jid;
 
			}
 

	
 
			const JID &getJID() const {
 
				return jid;
 
			}
 

	
 
			void setDesc(const std::string &desc) {
 
				this->desc = desc;
 
			}
 

	
 
			const std::string &getDesc() const {
 
				return desc;
 
			}
 

	
 
			void setPrompt(const std::string &prompt) {
 
				this->prompt = prompt;
 
			}
 

	
 
			const std::string &getPrompt() const {
 
				return prompt;
 
			}
 

	
 
		private:
 
			JID jid;
 
			std::string desc;
 
			std::string prompt;
 
	};
 
}
include/Swiften/Elements/PubSubItem.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Elements/PubSubItem.h>
 

	
 
namespace Swift {
 

	
 
PubSubItem::PubSubItem() {
 
}
 

	
 
}
include/Swiften/Elements/PubSubItem.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 

	
 
#include <string>
 
#include <Swiften/Elements/Payload.h>
 

	
 
namespace Swift {
 
	class PubSubItem : public Payload {
 
		public:
 
			PubSubItem();
 

	
 
			void addPayload(boost::shared_ptr<Payload> payload) {
 
				payloads.push_back(payload);
 
			}
 

	
 
			const std::vector<boost::shared_ptr<Payload> > getPayloads() const {
 
				return payloads;
 
			}
 
			
 
			template<typename T>
 
			const std::vector<boost::shared_ptr<T> > getPayloads() const {
 
				std::vector<boost::shared_ptr<T> > matched_payloads;
 
				for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
 
					boost::shared_ptr<T> result = boost::dynamic_pointer_cast<T>(*i);
 
					if (result) {
 
						matched_payloads.push_back(result);
 
					}
 
				}
 
				
 
				return matched_payloads;
 
				
 
			}
 

	
 
			template<typename T>
 
			const boost::shared_ptr<T> getPayload() const {
 
				boost::shared_ptr<T> result;
 
				for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
 
					result = boost::dynamic_pointer_cast<T>(*i);
 
					if (result) {
 
						return result;
 
					}
 
				}
 
				
 
				return result;
 
			}
 

	
 
			const std::string& getId() const { return id; }
 

	
 
			void setId(const std::string& id) { 
 
				this->id = id;
 
			}
 

	
 
		private:
 
			std::vector<boost::shared_ptr<Payload> > payloads;
 
			std::string id;
 
	};
 
}
include/Swiften/Elements/PubSubPayload.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Elements/PubSubPayload.h>
 

	
 
namespace Swift {
 

	
 
PubSubPayload::PubSubPayload() {
 
}
 

	
 
}
include/Swiften/Elements/PubSubPayload.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 

	
 
#include <string>
 
#include <Swiften/Elements/Payload.h>
 

	
 
namespace Swift {
 
	class PubSubPayload : public Payload {
 
		public:
 
			PubSubPayload();
 

	
 
			void addPayload(boost::shared_ptr<Payload> payload) {
 
				payloads.push_back(payload);
 
			}
 

	
 
			const std::vector<boost::shared_ptr<Payload> > getPayloads() const {
 
				return payloads;
 
			}
 

	
 
			template<typename T>
 
			const std::vector<boost::shared_ptr<T> > getPayloads() const {
 
				std::vector<boost::shared_ptr<T> > matched_payloads;
 
				for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
 
					boost::shared_ptr<T> result = boost::dynamic_pointer_cast<T>(*i);
 
					if (result) {
 
						matched_payloads.push_back(result);
 
					}
 
				}
 
				
 
				return matched_payloads;
 
				
 
			}
 

	
 
			template<typename T>
 
			const boost::shared_ptr<T> getPayload() const {
 
				boost::shared_ptr<T> result;
 
				for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) {
 
					result = boost::dynamic_pointer_cast<T>(*i);
 
					if (result) {
 
						return result;
 
					}
 
				}
 
				
 
				return result;
 
			}
 

	
 
		private:
 
			std::vector<boost::shared_ptr<Payload> > payloads;
 
	};
 
}
include/Swiften/Elements/PubSubPublishPayload.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Elements/PubSubPublishPayload.h>
 

	
 
namespace Swift {
 

	
 
PubSubPublishPayload::PubSubPublishPayload(const std::string &node) :
 
	node(node) {
 
		
 
	}
 

	
 
}
include/Swiften/Elements/PubSubPublishPayload.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 

	
 
#include <string>
 
#include <Swiften/Elements/Payload.h>
 
#include <Swiften/Elements/PubSubItem.h>
 
#include <Swiften/JID/JID.h>
 

	
 
namespace Swift {
 
	class PubSubPublishPayload : public Payload {
 
		public:
 
			enum Type { None, Pending, Subscribed, Unconfigured };
 

	
 
			PubSubPublishPayload(const std::string &node = "");
 

	
 
			void setNode(const std::string &node) {
 
				this->node = node;
 
			}
 

	
 
			const std::string &getNode() const {
 
				return node;
 
			}
 

	
 
			void addItem(const boost::shared_ptr<Payload> &item) {
 
				items.push_back(item);
 
			}
 

	
 
			const std::vector<boost::shared_ptr<Payload> > &getItems() const {
 
				return items;
 
			}
 

	
 
		private:
 
			std::string node;
 
			std::vector<boost::shared_ptr<Payload> > items;
 
	};
 
}
include/Swiften/Elements/PubSubSubscribePayload.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Elements/PubSubSubscribePayload.h>
 

	
 
namespace Swift {
 

	
 
PubSubSubscribePayload::PubSubSubscribePayload(const JID &jid, const std::string &node) :
 
	jid(jid), node(node) {
 
		
 
	}
 

	
 
}
include/Swiften/Elements/PubSubSubscribePayload.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 

	
 
#include <string>
 
#include <Swiften/Elements/Payload.h>
 
#include <Swiften/JID/JID.h>
 

	
 
namespace Swift {
 
	class PubSubSubscribePayload : public Payload {
 
		public:
 
			PubSubSubscribePayload(const JID &jid = JID(), const std::string &node = "");
 

	
 
			void setJID(const JID &jid) {
 
				this->jid = jid;
 
			}
 

	
 
			const JID &getJID() const {
 
				return jid;
 
			}
 

	
 
			void setNode(const std::string &node) {
 
				this->node = node;
 
			}
 

	
 
			const std::string &getNode() const {
 
				return node;
 
			}
 

	
 
		private:
 
			JID jid;
 
			std::string node;
 
	};
 
}
include/Swiften/Elements/PubSubSubscriptionPayload.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Elements/PubSubSubscriptionPayload.h>
 

	
 
namespace Swift {
 

	
 
PubSubSubscriptionPayload::PubSubSubscriptionPayload(const JID &jid, const std::string &node) :
 
	jid(jid), node(node), type(None) {
 
		
 
	}
 

	
 
}
include/Swiften/Elements/PubSubSubscriptionPayload.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 

	
 
#include <string>
 
#include <Swiften/Elements/Payload.h>
 
#include <Swiften/JID/JID.h>
 

	
 
namespace Swift {
 
	class PubSubSubscriptionPayload : public Payload {
 
		public:
 
			enum Type { None, Pending, Subscribed, Unconfigured };
 

	
 
			PubSubSubscriptionPayload(const JID &jid = JID(), const std::string &node = "");
 

	
 
			void setJID(const JID &jid) {
 
				this->jid = jid;
 
			}
 

	
 
			const JID &getJID() const {
 
				return jid;
 
			}
 

	
 
			void setNode(const std::string &node) {
 
				this->node = node;
 
			}
 

	
 
			const std::string &getNode() const {
 
				return node;
 
			}
 

	
 
			void setId(const std::string &id) {
 
				this->id = id;
 
			}
 

	
 
			const std::string &getId() const {
 
				return id;
 
			}
 

	
 
			void setType(const Type &type) {
 
				this->type = type;
 
			}
 

	
 
			const Type &getType() const {
 
				return type;
 
			}
 

	
 
		private:
 
			JID jid;
 
			std::string node;
 
			std::string id;
 
			Type type;
 
	};
 
}
include/Swiften/Network/DummyNetworkFactories.cpp
Show inline comments
 
@@ -18,6 +18,7 @@ DummyNetworkFactories::DummyNetworkFactories(EventLoop* eventLoop) {
 
	domainNameResolver = new PlatformDomainNameResolver(eventLoop);
 
	connectionServerFactory = new DummyConnectionServerFactory(eventLoop);
 
	m_platformXMLParserFactory =  new PlatformXMLParserFactory();
 
	this->eventLoop = eventLoop;
 
}
 

	
 
DummyNetworkFactories::~DummyNetworkFactories() {
include/Swiften/Network/DummyNetworkFactories.h
Show inline comments
 
@@ -41,6 +41,10 @@ namespace Swift {
 
				return m_platformXMLParserFactory;
 
			}
 

	
 
			EventLoop *getEventLoop() const {
 
				return eventLoop;
 
			}
 

	
 
            Swift::TLSContextFactory* getTLSContextFactory() const {
 
                return 0;
 
            }
 
@@ -55,5 +59,6 @@ namespace Swift {
 
			ConnectionFactory* connectionFactory;
 
			DomainNameResolver* domainNameResolver;
 
			ConnectionServerFactory* connectionServerFactory;
 
			EventLoop *eventLoop;
 
	};
 
}
include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Parser/PayloadParsers/GatewayPayloadParser.h>
 

	
 
#include <boost/lexical_cast.hpp>
 

	
 
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
 
#include <Swiften/Parser/PayloadParserFactory.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Elements/MUCOccupant.h>
 
#include <Swiften/Parser/Tree/TreeReparser.h>
 

	
 
namespace Swift {
 

	
 
void GatewayPayloadParser::handleTree(ParserElement::ref root) {
 
	foreach (ParserElement::ref child, root->getAllChildren()) {
 
		if (child->getName() == "desc") {
 
			getPayloadInternal()->setDesc(child->getText());
 
		}
 
		else if (child->getName() == "prompt") {
 
			getPayloadInternal()->setPrompt(child->getText());
 
		}
 
		else if (child->getName() == "jid") {
 
			getPayloadInternal()->setJID(child->getText());
 
		}
 
	}
 
}
 

	
 
}
include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <boost/optional.hpp>
 

	
 
#include <Swiften/Elements/GatewayPayload.h>
 
#include <Swiften/Parser/GenericPayloadTreeParser.h>
 
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
 

	
 
namespace Swift {
 
	class GatewayPayloadParser : public GenericPayloadTreeParser<GatewayPayload> {
 
		public:
 
			GatewayPayloadParser() {}
 
			virtual void handleTree(ParserElement::ref root);
 
	};
 
}
include/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Parser/PayloadParsers/PubSubItemParser.h>
 

	
 
#include <boost/lexical_cast.hpp>
 

	
 
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
 
#include <Swiften/Parser/PayloadParserFactory.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Elements/MUCOccupant.h>
 
#include <Swiften/Parser/Tree/TreeReparser.h>
 

	
 
namespace Swift {
 

	
 
void PubSubItemParser::handleTree(ParserElement::ref root) {
 
	std::string id = root->getAttributes().getAttribute("id");
 
	if (!id.empty()) {
 
		getPayloadInternal()->setId(id);
 
	}
 

	
 
	foreach (ParserElement::ref child, root->getAllChildren()) {
 
		getPayloadInternal()->addPayload(TreeReparser::parseTree(child, factories));
 
	}
 
}
 

	
 
}
include/Swiften/Parser/PayloadParsers/PubSubItemParser.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <boost/optional.hpp>
 

	
 
#include <Swiften/Elements/PubSubItem.h>
 
#include <Swiften/Parser/GenericPayloadTreeParser.h>
 
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
 

	
 
namespace Swift {
 
	class PayloadParserFactoryCollection;
 
	class PubSubItemParser : public GenericPayloadTreeParser<PubSubItem> {
 
		public:
 
			PubSubItemParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
 
			virtual void handleTree(ParserElement::ref root);
 
		private:
 
			PayloadParserFactoryCollection* factories;
 
	};
 
}
include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Parser/PayloadParsers/PubSubPayloadParser.h>
 

	
 
#include <boost/lexical_cast.hpp>
 

	
 
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
 
#include <Swiften/Parser/PayloadParserFactory.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Elements/MUCOccupant.h>
 
#include <Swiften/Parser/Tree/TreeReparser.h>
 

	
 
namespace Swift {
 

	
 
void PubSubPayloadParser::handleTree(ParserElement::ref root) {
 
	foreach (ParserElement::ref child, root->getAllChildren()) {
 
		getPayloadInternal()->addPayload(TreeReparser::parseTree(child, factories));
 
	}
 
}
 

	
 
}
include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <boost/optional.hpp>
 

	
 
#include <Swiften/Elements/PubSubPayload.h>
 
#include <Swiften/Parser/GenericPayloadTreeParser.h>
 
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
 

	
 
namespace Swift {
 
	class PayloadParserFactoryCollection;
 
	class PubSubPayloadParser : public GenericPayloadTreeParser<PubSubPayload> {
 
		public:
 
			PubSubPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
 
			virtual void handleTree(ParserElement::ref root);
 
		private:
 
			PayloadParserFactoryCollection* factories;
 
	};
 
}
include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.h>
 

	
 
#include <boost/lexical_cast.hpp>
 

	
 
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
 
#include <Swiften/Parser/PayloadParserFactory.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Elements/MUCOccupant.h>
 
#include <Swiften/Parser/Tree/TreeReparser.h>
 

	
 
namespace Swift {
 

	
 
void PubSubPublishPayloadParser::handleTree(ParserElement::ref root) {
 
	std::string node = root->getAttributes().getAttribute("node");
 
	if (!node.empty()) {
 
		getPayloadInternal()->setNode(node);
 
	}
 

	
 
	foreach (ParserElement::ref child, root->getAllChildren()) {
 
		getPayloadInternal()->addItem(TreeReparser::parseTree(child, factories));
 
	}
 
}
 

	
 
}
include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <boost/optional.hpp>
 

	
 
#include <Swiften/Elements/PubSubPublishPayload.h>
 
#include <Swiften/Parser/GenericPayloadTreeParser.h>
 
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
 

	
 
namespace Swift {
 
	class PayloadParserFactoryCollection;
 
	class PubSubPublishPayloadParser : public GenericPayloadTreeParser<PubSubPublishPayload> {
 
		public:
 
			PubSubPublishPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
 
			virtual void handleTree(ParserElement::ref root);
 
		private:
 
			PayloadParserFactoryCollection* factories;
 
	};
 
}
include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.h>
 

	
 
#include <boost/lexical_cast.hpp>
 

	
 
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
 
#include <Swiften/Parser/PayloadParserFactory.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Elements/MUCOccupant.h>
 
#include <Swiften/Parser/Tree/TreeReparser.h>
 

	
 
namespace Swift {
 

	
 
void PubSubSubscribePayloadParser::handleTree(ParserElement::ref root) {
 
	std::string node = root->getAttributes().getAttribute("node");
 
	if (!node.empty()) {
 
		getPayloadInternal()->setNode(node);
 
	}
 

	
 
	std::string jid = root->getAttributes().getAttribute("jid");
 
	if (!jid.empty()) {
 
		getPayloadInternal()->setJID(jid);
 
	}
 

	
 
}
 

	
 
}
include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <boost/optional.hpp>
 

	
 
#include <Swiften/Elements/PubSubSubscribePayload.h>
 
#include <Swiften/Parser/GenericPayloadTreeParser.h>
 
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
 

	
 
namespace Swift {
 
	class PayloadParserFactoryCollection;
 
	class PubSubSubscribePayloadParser : public GenericPayloadTreeParser<PubSubSubscribePayload> {
 
		public:
 
			PubSubSubscribePayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
 
			virtual void handleTree(ParserElement::ref root);
 
		private:
 
			PayloadParserFactoryCollection* factories;
 
	};
 
}
include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.h>
 

	
 
#include <boost/lexical_cast.hpp>
 

	
 
#include <Swiften/Parser/PayloadParserFactoryCollection.h>
 
#include <Swiften/Parser/PayloadParserFactory.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Elements/MUCOccupant.h>
 
#include <Swiften/Parser/Tree/TreeReparser.h>
 

	
 
namespace Swift {
 

	
 
void PubSubSubscriptionPayloadParser::handleTree(ParserElement::ref root) {
 
	std::string node = root->getAttributes().getAttribute("node");
 
	if (!node.empty()) {
 
		getPayloadInternal()->setNode(node);
 
	}
 

	
 
	std::string jid = root->getAttributes().getAttribute("jid");
 
	if (!jid.empty()) {
 
		getPayloadInternal()->setJID(jid);
 
	}
 

	
 
	std::string id = root->getAttributes().getAttribute("subid");
 
	if (!id.empty()) {
 
		getPayloadInternal()->setId(id);
 
	}
 

	
 
	std::string type = root->getAttributes().getAttribute("subscription");
 
	if (type == "none") {
 
		getPayloadInternal()->setType(PubSubSubscriptionPayload::None);
 
	}
 
	else if (type == "subscribed") {
 
		getPayloadInternal()->setType(PubSubSubscriptionPayload::Subscribed);
 
	}
 
	else if (type == "pending") {
 
		getPayloadInternal()->setType(PubSubSubscriptionPayload::Pending);
 
	}
 
	else if (type == "unconfigured") {
 
		getPayloadInternal()->setType(PubSubSubscriptionPayload::Unconfigured);
 
	}
 

	
 
}
 

	
 
}
include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2012 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <boost/optional.hpp>
 

	
 
#include <Swiften/Elements/PubSubSubscriptionPayload.h>
 
#include <Swiften/Parser/GenericPayloadTreeParser.h>
 
#include <Swiften/Parser/PayloadParsers/MUCItemParser.h>
 

	
 
namespace Swift {
 
	class PayloadParserFactoryCollection;
 
	class PubSubSubscriptionPayloadParser : public GenericPayloadTreeParser<PubSubSubscriptionPayload> {
 
		public:
 
			PubSubSubscriptionPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {}
 
			virtual void handleTree(ParserElement::ref root);
 
		private:
 
			PayloadParserFactoryCollection* factories;
 
	};
 
}
include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
 
#include <Swiften/Serializer/XML/XMLTextNode.h>
 
#include <Swiften/Serializer/XML/XMLElement.h>
 
#include <Swiften/Serializer/PayloadSerializerCollection.h>
 

	
 
namespace Swift {
 

	
 
GatewayPayloadSerializer::GatewayPayloadSerializer()
 
	: GenericPayloadSerializer<GatewayPayload>() {
 
}
 

	
 
std::string GatewayPayloadSerializer::serializePayload(boost::shared_ptr<GatewayPayload> payload)  const {
 
	XMLElement query("query", "jabber:iq:gateway");
 

	
 
	if (payload->getJID().isValid()) {
 
		boost::shared_ptr<XMLElement> jid(new XMLElement("jid", "", payload->getJID().toBare().toString()));
 
		query.addNode(jid);
 
	}
 

	
 
	if (!payload->getDesc().empty()) {
 
		boost::shared_ptr<XMLElement> desc(new XMLElement("desc", "", payload->getDesc()));
 
		query.addNode(desc);
 
	}
 

	
 
	if (!payload->getPrompt().empty()) {
 
		boost::shared_ptr<XMLElement> prompt(new XMLElement("prompt", "", payload->getPrompt()));
 
		query.addNode(prompt);
 
	}
 

	
 
	return query.serialize();
 
}
 

	
 
}
include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <Swiften/Serializer/GenericPayloadSerializer.h>
 
#include <Swiften/Elements/GatewayPayload.h>
 

	
 
namespace Swift {
 
	class GatewayPayloadSerializer : public GenericPayloadSerializer<GatewayPayload> {
 
		public:
 
			GatewayPayloadSerializer();
 

	
 
			virtual std::string serializePayload(boost::shared_ptr<GatewayPayload> item)  const;
 
	};
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
 
#include <Swiften/Serializer/XML/XMLTextNode.h>
 
#include <Swiften/Serializer/XML/XMLElement.h>
 
#include <Swiften/Serializer/PayloadSerializerCollection.h>
 

	
 
namespace Swift {
 

	
 
PubSubItemSerializer::PubSubItemSerializer(PayloadSerializerCollection *serializers) : 
 
	GenericPayloadSerializer<PubSubItem>(), serializers(serializers) {
 
}
 

	
 
std::string PubSubItemSerializer::serializePayload(boost::shared_ptr<PubSubItem> payload)  const {
 
	XMLElement item("item");
 
	if (!payload->getId().empty()) {
 
		item.setAttribute("id", payload->getId());
 
	}
 

	
 
	if (!payload->getPayloads().empty()) {		
 
		foreach(boost::shared_ptr<Payload> subPayload, payload->getPayloads()) {
 
			PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload);
 
			if (serializer) {
 
				item.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(subPayload))));
 
			}
 
		}
 
	}
 

	
 
	return item.serialize();
 
}
 

	
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <Swiften/Serializer/GenericPayloadSerializer.h>
 
#include <Swiften/Elements/PubSubItem.h>
 

	
 
namespace Swift {
 
	class PayloadSerializerCollection;
 
	class PubSubItemSerializer : public GenericPayloadSerializer<PubSubItem> {
 
		public:
 
			PubSubItemSerializer(PayloadSerializerCollection *serializers);
 

	
 
			virtual std::string serializePayload(boost::shared_ptr<PubSubItem> item)  const;
 
		private:
 
			PayloadSerializerCollection *serializers;
 
	};
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
 
#include <Swiften/Serializer/XML/XMLTextNode.h>
 
#include <Swiften/Serializer/XML/XMLElement.h>
 
#include <Swiften/Serializer/PayloadSerializerCollection.h>
 

	
 
namespace Swift {
 

	
 
PubSubPayloadSerializer::PubSubPayloadSerializer(PayloadSerializerCollection *serializers)
 
	: GenericPayloadSerializer<PubSubPayload>(),
 
	serializers(serializers) {
 
}
 

	
 
std::string PubSubPayloadSerializer::serializePayload(boost::shared_ptr<PubSubPayload> payload)  const {
 
	XMLElement pubsub("pubsub", "http://jabber.org/protocol/pubsub");
 

	
 
	if (!payload->getPayloads().empty()) {		
 
		foreach(boost::shared_ptr<Payload> subPayload, payload->getPayloads()) {
 
			PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload);
 
			if (serializer) {
 
				pubsub.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(subPayload))));
 
			}
 
		}
 
	}
 

	
 
	return pubsub.serialize();
 
}
 

	
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <Swiften/Serializer/GenericPayloadSerializer.h>
 
#include <Swiften/Elements/PubSubPayload.h>
 

	
 
namespace Swift {
 
	class PayloadSerializerCollection;
 

	
 
	class PubSubPayloadSerializer : public GenericPayloadSerializer<PubSubPayload> {
 
		public:
 
			PubSubPayloadSerializer(PayloadSerializerCollection *serializers);
 

	
 
			virtual std::string serializePayload(boost::shared_ptr<PubSubPayload> item)  const;
 
		private:
 
			PayloadSerializerCollection *serializers;
 
	};
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
 
#include <Swiften/Serializer/XML/XMLTextNode.h>
 
#include <Swiften/Serializer/XML/XMLElement.h>
 
#include <Swiften/Serializer/PayloadSerializerCollection.h>
 

	
 
namespace Swift {
 

	
 
PubSubPublishPayloadSerializer::PubSubPublishPayloadSerializer(PayloadSerializerCollection *serializers)
 
	: GenericPayloadSerializer<PubSubPublishPayload>(),
 
	serializers(serializers) {
 
}
 

	
 
std::string PubSubPublishPayloadSerializer::serializePayload(boost::shared_ptr<PubSubPublishPayload> payload)  const {
 
	XMLElement publish("publish");
 

	
 
	if (!payload->getNode().empty()) {
 
		publish.setAttribute("node", payload->getNode());
 
	}
 

	
 
	if (!payload->getItems().empty()) {		
 
		foreach(boost::shared_ptr<Payload> subPayload, payload->getItems()) {
 
			PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload);
 
			if (serializer) {
 
				publish.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(subPayload))));
 
			}
 
		}
 
	}
 

	
 
	return publish.serialize();
 
}
 

	
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <Swiften/Serializer/GenericPayloadSerializer.h>
 
#include <Swiften/Elements/PubSubPublishPayload.h>
 

	
 
namespace Swift {
 
	class PayloadSerializerCollection;
 

	
 
	class PubSubPublishPayloadSerializer : public GenericPayloadSerializer<PubSubPublishPayload> {
 
		public:
 
			PubSubPublishPayloadSerializer(PayloadSerializerCollection *serializers);
 

	
 
			virtual std::string serializePayload(boost::shared_ptr<PubSubPublishPayload> item)  const;
 
		private:
 
			PayloadSerializerCollection *serializers;
 
	};
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
 
#include <Swiften/Serializer/XML/XMLTextNode.h>
 
#include <Swiften/Serializer/XML/XMLElement.h>
 
#include <Swiften/Serializer/PayloadSerializerCollection.h>
 

	
 
namespace Swift {
 

	
 
PubSubSubscribePayloadSerializer::PubSubSubscribePayloadSerializer()
 
	: GenericPayloadSerializer<PubSubSubscribePayload>() {
 
}
 

	
 
std::string PubSubSubscribePayloadSerializer::serializePayload(boost::shared_ptr<PubSubSubscribePayload> payload)  const {
 
	XMLElement subscribe("subscribe");
 

	
 
	if (!payload->getJID().isValid()) {
 
		subscribe.setAttribute("jid", payload->getJID().toBare().toString());
 
	}
 

	
 
	if (!payload->getNode().empty()) {
 
		subscribe.setAttribute("node", payload->getNode());
 
	}
 

	
 
	return subscribe.serialize();
 
}
 

	
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <Swiften/Serializer/GenericPayloadSerializer.h>
 
#include <Swiften/Elements/PubSubSubscribePayload.h>
 

	
 
namespace Swift {
 
	class PubSubSubscribePayloadSerializer : public GenericPayloadSerializer<PubSubSubscribePayload> {
 
		public:
 
			PubSubSubscribePayloadSerializer();
 

	
 
			virtual std::string serializePayload(boost::shared_ptr<PubSubSubscribePayload> item)  const;
 
	};
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.cpp
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#include <Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.h>
 
#include <Swiften/Base/foreach.h>
 
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
 
#include <Swiften/Serializer/XML/XMLTextNode.h>
 
#include <Swiften/Serializer/XML/XMLElement.h>
 
#include <Swiften/Serializer/PayloadSerializerCollection.h>
 

	
 
namespace Swift {
 

	
 
PubSubSubscriptionPayloadSerializer::PubSubSubscriptionPayloadSerializer()
 
	: GenericPayloadSerializer<PubSubSubscriptionPayload>() {
 
}
 

	
 
std::string PubSubSubscriptionPayloadSerializer::serializePayload(boost::shared_ptr<PubSubSubscriptionPayload> payload)  const {
 
	XMLElement subscription("subscription");
 

	
 
	if (!payload->getJID().isValid()) {
 
		subscription.setAttribute("jid", payload->getJID().toBare().toString());
 
	}
 

	
 
	if (!payload->getNode().empty()) {
 
		subscription.setAttribute("node", payload->getNode());
 
	}
 

	
 
	switch (payload->getType()) {
 
		case PubSubSubscriptionPayload::None:
 
			subscription.setAttribute("subscription", "none");
 
			break;
 
		case PubSubSubscriptionPayload::Subscribed:
 
			subscription.setAttribute("subscription", "subscribed");
 
			break;
 
		case PubSubSubscriptionPayload::Unconfigured:
 
			subscription.setAttribute("subscription", "unconfigured");
 
			break;
 
		case PubSubSubscriptionPayload::Pending:
 
			subscription.setAttribute("subscription", "pending");
 
			break;
 
	}
 

	
 
	return subscription.serialize();
 
}
 

	
 
}
include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.h
Show inline comments
 
new file 100644
 
/*
 
 * Copyright (c) 2011 Jan Kaluza
 
 * Licensed under the Simplified BSD license.
 
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 
 */
 

	
 
#pragma once
 

	
 
#include <Swiften/Serializer/GenericPayloadSerializer.h>
 
#include <Swiften/Elements/PubSubSubscriptionPayload.h>
 

	
 
namespace Swift {
 
	class PubSubSubscriptionPayloadSerializer : public GenericPayloadSerializer<PubSubSubscriptionPayload> {
 
		public:
 
			PubSubSubscriptionPayloadSerializer();
 

	
 
			virtual std::string serializePayload(boost::shared_ptr<PubSubSubscriptionPayload> item)  const;
 
	};
 
}
include/Swiften/Server/Server.cpp
Show inline comments
 
@@ -149,7 +149,7 @@ void Server::handleSessionFinished(boost::shared_ptr<ServerFromClientSession> se
 
			boost::bind(&Server::handleSessionFinished, this, session));
 
}
 

	
 
void Server::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert) {
 
void Server::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert) {
 
	tlsFactory = tlsContextFactory;
 
	this->cert = cert;
 
}
include/Swiften/Server/Server.h
Show inline comments
 
@@ -21,7 +21,7 @@
 
#include "Swiften/Entity/Entity.h"
 
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
 
#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h"
 
#include "Swiften/TLS/PKCS12Certificate.h"
 
#include <Swiften/TLS/CertificateWithKey.h>
 
#include <Swiften/Parser/PlatformXMLParserFactory.h>
 

	
 
namespace Swift {
 
@@ -60,7 +60,7 @@ namespace Swift {
 
			boost::signal<void (const SafeByteArray&)> onDataRead;
 
			boost::signal<void (const SafeByteArray&)> onDataWritten;
 

	
 
			void addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert);
 
			void addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert);
 

	
 
		private:
 
			void handleNewClientConnection(boost::shared_ptr<Connection> c);
 
@@ -84,7 +84,7 @@ namespace Swift {
 
			StanzaChannel *stanzaChannel_;
 
			IQRouter *iqRouter_;
 
			TLSServerContextFactory *tlsFactory;
 
			PKCS12Certificate cert;
 
			CertificateWithKey::ref cert;
 
			PlatformXMLParserFactory *parserFactory_;
 
	};
 
}
include/Swiften/Server/ServerFromClientSession.cpp
Show inline comments
 
@@ -27,6 +27,7 @@
 
#include <Swiften/Elements/StartTLSRequest.h>
 
#include <Swiften/Elements/TLSProceed.h>
 
#include <iostream>
 
#include <Swiften/TLS/CertificateWithKey.h>
 

	
 
namespace Swift {
 

	
 
@@ -162,7 +163,7 @@ void ServerFromClientSession::handleSessionFinished(const boost::optional<Sessio
 
	userRegistry_->stopLogin(JID(user_, getLocalJID().getDomain()), this);
 
}
 

	
 
void ServerFromClientSession::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert) {
 
void ServerFromClientSession::addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert) {
 
	tlsLayer = new TLSServerLayer(tlsContextFactory);
 
	if (!tlsLayer->setServerCertificate(cert)) {
 
// 		std::cout << "error\n";
include/Swiften/Server/ServerFromClientSession.h
Show inline comments
 
@@ -15,6 +15,7 @@
 
#include <Swiften/JID/JID.h>
 
#include <Swiften/Network/Connection.h>
 
#include <Swiften/Base/ByteArray.h>
 
#include <Swiften/TLS/CertificateWithKey.h>
 

	
 
namespace Swift {
 
	class ProtocolHeader;
 
@@ -49,7 +50,7 @@ namespace Swift {
 
				return user_;
 
			}
 

	
 
			void addTLSEncryption(TLSServerContextFactory* tlsContextFactory, const PKCS12Certificate& cert);
 
			void addTLSEncryption(TLSServerContextFactory* tlsContextFactory, CertificateWithKey::ref cert);
 

	
 
			Swift::JID getBareJID() {
 
				return Swift::JID(user_, getLocalJID().getDomain());
include/Swiften/Server/ServerStanzaChannel.cpp
Show inline comments
 
@@ -32,11 +32,13 @@ void ServerStanzaChannel::addSession(boost::shared_ptr<ServerFromClientSession>
 
	sessions[session->getRemoteJID().toBare().toString()].push_back(session);
 
	session->onSessionFinished.connect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session));
 
	session->onElementReceived.connect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session));
 
	session->onDataRead.connect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session));
 
}
 

	
 
void ServerStanzaChannel::removeSession(boost::shared_ptr<ServerFromClientSession> session) {
 
	session->onSessionFinished.disconnect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session));
 
	session->onElementReceived.disconnect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session));
 
	session->onDataRead.disconnect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session));
 
	std::list<boost::shared_ptr<ServerFromClientSession> > &lst = sessions[session->getRemoteJID().toBare().toString()];
 
	lst.erase(std::remove(lst.begin(), lst.end(), session), lst.end());
 
}
 
@@ -53,6 +55,15 @@ void ServerStanzaChannel::sendPresence(boost::shared_ptr<Presence> presence) {
 
	send(presence);
 
}
 

	
 
void ServerStanzaChannel::handleDataRead(const SafeByteArray &data, const boost::shared_ptr<ServerFromClientSession> &session) {
 
	if (safeByteArrayToString(data).find("</stream:stream>") != std::string::npos) {
 
		Swift::Presence::ref presence = Swift::Presence::create();
 
		presence->setFrom(session->getRemoteJID());
 
		presence->setType(Swift::Presence::Unavailable);
 
		onPresenceReceived(presence);
 
	}
 
}
 

	
 
void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr<Element> element, bool last) {
 
	std::vector<boost::shared_ptr<ServerFromClientSession> > candidateSessions;
 
	for (std::list<boost::shared_ptr<ServerFromClientSession> >::const_iterator i = sessions[to.toBare().toString()].begin(); i != sessions[to.toBare().toString()].end(); ++i) {
include/Swiften/Server/ServerStanzaChannel.h
Show inline comments
 
@@ -41,6 +41,7 @@ namespace Swift {
 
			void send(boost::shared_ptr<Stanza> stanza);
 
			void handleSessionFinished(const boost::optional<Session::SessionError>&, const boost::shared_ptr<ServerFromClientSession> &session);
 
			void handleElement(boost::shared_ptr<Element> element, const boost::shared_ptr<ServerFromClientSession> &session);
 
			void handleDataRead(const SafeByteArray &data, const boost::shared_ptr<ServerFromClientSession> &session);
 
			void handleSessionInitialized();
 

	
 
		private:
include/Swiften/StreamStack/TLSServerLayer.cpp
Show inline comments
 
@@ -37,7 +37,7 @@ void TLSServerLayer::handleDataRead(const SafeByteArray& data) {
 
	context->handleDataFromNetwork(data);
 
}
 

	
 
bool TLSServerLayer::setServerCertificate(const PKCS12Certificate& certificate) {
 
bool TLSServerLayer::setServerCertificate(CertificateWithKey::ref certificate) {
 
	return context->setServerCertificate(certificate);
 
}
 

	
include/Swiften/StreamStack/TLSServerLayer.h
Show inline comments
 
@@ -9,6 +9,7 @@
 
#include "Swiften/Base/SafeByteArray.h"
 
#include "Swiften/StreamStack/StreamLayer.h"
 
#include "Swiften/TLS/Certificate.h"
 
#include <Swiften/TLS/CertificateWithKey.h>
 
#include "Swiften/TLS/CertificateVerificationError.h"
 

	
 
namespace Swift {
 
@@ -22,7 +23,7 @@ namespace Swift {
 
			~TLSServerLayer();
 

	
 
			void connect();
 
			bool setServerCertificate(const PKCS12Certificate&);
 
			bool setServerCertificate(CertificateWithKey::ref cert);
 

	
 
			Certificate::ref getPeerCertificate() const;
 
			boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const;
include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp
Show inline comments
 
@@ -14,6 +14,13 @@
 
#include <openssl/err.h>
 
#include <openssl/pkcs12.h>
 

	
 
#include "log4cxx/logger.h"
 
#include "log4cxx/consoleappender.h"
 
#include "log4cxx/patternlayout.h"
 
#include "log4cxx/propertyconfigurator.h"
 
using namespace log4cxx;
 
static LoggerPtr logger = Logger::getLogger("OpenSSLServerContext");
 

	
 

	
 
#include "Swiften/TLS/OpenSSL/OpenSSLServerContext.h"
 
#include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h"
 
@@ -179,7 +186,7 @@ void OpenSSLServerContext::sendPendingDataToApplication() {
 

	
 
bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certificate) {
 
	if (certificate.isNull()) {
 
// 		std::cout << "error 1\n";
 
		LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate can't be loaded.");
 
		return false;
 
	}
 

	
 
@@ -189,7 +196,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi
 
	boost::shared_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(bio, NULL), PKCS12_free);
 
	BIO_free(bio);
 
	if (!pkcs12) {
 
// 		std::cout << "error 2\n";
 
		LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format.");
 
		return false;
 
	}
 

	
 
@@ -199,7 +206,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi
 
	STACK_OF(X509)* caCertsPtr = 0;
 
	int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(certificate.getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr);
 
	if (result != 1) { 
 
// 		std::cout << "error 3\n";
 
		LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format.");
 
		return false;
 
	}
 
	boost::shared_ptr<X509> cert(certPtr, X509_free);
 
@@ -208,11 +215,11 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi
 

	
 
	// Use the key & certificates
 
	if (SSL_CTX_use_certificate(context_, cert.get()) != 1) {
 
// 		std::cout << "error 4\n";
 
		LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this certificate");
 
		return false;
 
	}
 
	if (SSL_CTX_use_PrivateKey(context_, privateKey.get()) != 1) {
 
// 		std::cout << "error 5\n";
 
		LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this private key");
 
		return false;
 
	}
 
	return true;
include/Swiften/TLS/TLSServerContext.h
Show inline comments
 
@@ -11,6 +11,7 @@
 

	
 
#include "Swiften/Base/SafeByteArray.h"
 
#include "Swiften/TLS/Certificate.h"
 
#include <Swiften/TLS/CertificateWithKey.h>
 
#include "Swiften/TLS/CertificateVerificationError.h"
 

	
 
namespace Swift {
 
@@ -22,7 +23,7 @@ namespace Swift {
 

	
 
			virtual void connect() = 0;
 

	
 
			virtual bool setServerCertificate(const PKCS12Certificate& cert) = 0;
 
			virtual bool setServerCertificate(CertificateWithKey::ref cert) = 0;
 

	
 
			virtual void handleDataFromNetwork(const SafeByteArray&) = 0;
 
			virtual void handleDataFromApplication(const SafeByteArray&) = 0;
include/transport/gatewayresponder.h
Show inline comments
 
new file 100644
 
/**
 
 * libtransport -- C++ library for easy XMPP Transports development
 
 *
 
 * Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * 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 General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#pragma once
 

	
 
#include <vector>
 
#include "Swiften/Swiften.h"
 
#include "Swiften/Queries/Responder.h"
 
#include "Swiften/Elements/GatewayPayload.h"
 

	
 
namespace Transport {
 

	
 
class UserManager;
 

	
 
class GatewayResponder : public Swift::Responder<Swift::GatewayPayload> {
 
	public:
 
		GatewayResponder(Swift::IQRouter *router, UserManager *userManager);
 
		~GatewayResponder();
 

	
 
	private:
 
		virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::GatewayPayload> payload);
 
		virtual bool handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::GatewayPayload> payload);
 
		UserManager *m_userManager;
 
};
 

	
 
}
 
\ No newline at end of file
include/transport/pqxxbackend.h
Show inline comments
 
@@ -97,7 +97,10 @@ class PQXXBackend : public StorageBackend
 

	
 
	private:
 
		bool exec(const std::string &query, bool show_error = true);
 
		bool exec(pqxx::work &txn, const std::string &query, bool show_error = true);
 
		bool exec(pqxx::nontransaction &txn, const std::string &query, bool show_error = true);
 
		template<typename T>
 
		std::string quote(pqxx::nontransaction &txn, const T &t);
 

	
 
		Config *m_config;
 
		std::string m_prefix;
 

	
include/transport/usermanager.h
Show inline comments
 
@@ -104,6 +104,10 @@ class UserManager : public Swift::EntityCapsProvider {
 
			return m_userRegistry;
 
		}
 

	
 
		Component *getComponent() {
 
			return m_component;
 
		}
 

	
 
		/// Connects user manually.
 
		/// \param user JID of user.
 
		void connectUser(const Swift::JID &user);
msvc-deps/sqlite3/CMakeLists.txt
Show inline comments
 
new file 100644
 
cmake_minimum_required(VERSION 2.6)
 
FILE(GLOB SRC *.c *.h)
 
 
ADD_LIBRARY(sqlite3 STATIC ${HEADERS} ${SRC})
 
 
INSTALL(TARGETS sqlite3 LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries)
 
\ No newline at end of file
msvc-deps/sqlite3/shell.c
Show inline comments
 
new file 100644
 
/*
 
** 2001 September 15
 
**
 
** The author disclaims copyright to this source code.  In place of
 
** a legal notice, here is a blessing:
 
**
 
**    May you do good and not evil.
 
**    May you find forgiveness for yourself and forgive others.
 
**    May you share freely, never taking more than you give.
 
**
 
*************************************************************************
 
** This file contains code to implement the "sqlite" command line
 
** utility for accessing SQLite databases.
 
*/
 
#if (defined(_WIN32) || defined(WIN32)) && !defined(_CRT_SECURE_NO_WARNINGS)
 
/* This needs to come before any includes for MSVC compiler */
 
#define _CRT_SECURE_NO_WARNINGS
 
#endif
 

	
 
/*
 
** Enable large-file support for fopen() and friends on unix.
 
*/
 
#ifndef SQLITE_DISABLE_LFS
 
# define _LARGE_FILE       1
 
# ifndef _FILE_OFFSET_BITS
 
#   define _FILE_OFFSET_BITS 64
 
# endif
 
# define _LARGEFILE_SOURCE 1
 
#endif
 

	
 
#include <stdlib.h>
 
#include <string.h>
 
#include <stdio.h>
 
#include <assert.h>
 
#include "sqlite3.h"
 
#include <ctype.h>
 
#include <stdarg.h>
 

	
 
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__)
 
# include <signal.h>
 
# if !defined(__RTP__) && !defined(_WRS_KERNEL)
 
#  include <pwd.h>
 
# endif
 
# include <unistd.h>
 
# include <sys/types.h>
 
#endif
 

	
 
#ifdef __OS2__
 
# include <unistd.h>
 
#endif
 

	
 
#ifdef HAVE_EDITLINE
 
# include <editline/editline.h>
 
#endif
 
#if defined(HAVE_READLINE) && HAVE_READLINE==1
 
# include <readline/readline.h>
 
# include <readline/history.h>
 
#endif
 
#if !defined(HAVE_EDITLINE) && (!defined(HAVE_READLINE) || HAVE_READLINE!=1)
 
# define readline(p) local_getline(p,stdin)
 
# define add_history(X)
 
# define read_history(X)
 
# define write_history(X)
 
# define stifle_history(X)
 
#endif
 

	
 
#if defined(_WIN32) || defined(WIN32)
 
# include <io.h>
 
#define isatty(h) _isatty(h)
 
#define access(f,m) _access((f),(m))
 
#else
 
/* Make sure isatty() has a prototype.
 
*/
 
extern int isatty(int);
 
#endif
 

	
 
#if defined(_WIN32_WCE)
 
/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty()
 
 * thus we always assume that we have a console. That can be
 
 * overridden with the -batch command line option.
 
 */
 
#define isatty(x) 1
 
#endif
 

	
 
/* True if the timer is enabled */
 
static int enableTimer = 0;
 

	
 
/* ctype macros that work with signed characters */
 
#define IsSpace(X)  isspace((unsigned char)X)
 
#define IsDigit(X)  isdigit((unsigned char)X)
 
#define ToLower(X)  (char)tolower((unsigned char)X)
 

	
 
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL)
 
#include <sys/time.h>
 
#include <sys/resource.h>
 

	
 
/* Saved resource information for the beginning of an operation */
 
static struct rusage sBegin;
 

	
 
/*
 
** Begin timing an operation
 
*/
 
static void beginTimer(void){
 
  if( enableTimer ){
 
    getrusage(RUSAGE_SELF, &sBegin);
 
  }
 
}
 

	
 
/* Return the difference of two time_structs in seconds */
 
static double timeDiff(struct timeval *pStart, struct timeval *pEnd){
 
  return (pEnd->tv_usec - pStart->tv_usec)*0.000001 + 
 
         (double)(pEnd->tv_sec - pStart->tv_sec);
 
}
 

	
 
/*
 
** Print the timing results.
 
*/
 
static void endTimer(void){
 
  if( enableTimer ){
 
    struct rusage sEnd;
 
    getrusage(RUSAGE_SELF, &sEnd);
 
    printf("CPU Time: user %f sys %f\n",
 
       timeDiff(&sBegin.ru_utime, &sEnd.ru_utime),
 
       timeDiff(&sBegin.ru_stime, &sEnd.ru_stime));
 
  }
 
}
 

	
 
#define BEGIN_TIMER beginTimer()
 
#define END_TIMER endTimer()
 
#define HAS_TIMER 1
 

	
 
#elif (defined(_WIN32) || defined(WIN32))
 

	
 
#include <windows.h>
 

	
 
/* Saved resource information for the beginning of an operation */
 
static HANDLE hProcess;
 
static FILETIME ftKernelBegin;
 
static FILETIME ftUserBegin;
 
typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME);
 
static GETPROCTIMES getProcessTimesAddr = NULL;
 

	
 
/*
 
** Check to see if we have timer support.  Return 1 if necessary
 
** support found (or found previously).
 
*/
 
static int hasTimer(void){
 
  if( getProcessTimesAddr ){
 
    return 1;
 
  } else {
 
    /* GetProcessTimes() isn't supported in WIN95 and some other Windows versions.
 
    ** See if the version we are running on has it, and if it does, save off
 
    ** a pointer to it and the current process handle.
 
    */
 
    hProcess = GetCurrentProcess();
 
    if( hProcess ){
 
      HINSTANCE hinstLib = LoadLibrary(TEXT("Kernel32.dll"));
 
      if( NULL != hinstLib ){
 
        getProcessTimesAddr = (GETPROCTIMES) GetProcAddress(hinstLib, "GetProcessTimes");
 
        if( NULL != getProcessTimesAddr ){
 
          return 1;
 
        }
 
        FreeLibrary(hinstLib); 
 
      }
 
    }
 
  }
 
  return 0;
 
}
 

	
 
/*
 
** Begin timing an operation
 
*/
 
static void beginTimer(void){
 
  if( enableTimer && getProcessTimesAddr ){
 
    FILETIME ftCreation, ftExit;
 
    getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelBegin, &ftUserBegin);
 
  }
 
}
 

	
 
/* Return the difference of two FILETIME structs in seconds */
 
static double timeDiff(FILETIME *pStart, FILETIME *pEnd){
 
  sqlite_int64 i64Start = *((sqlite_int64 *) pStart);
 
  sqlite_int64 i64End = *((sqlite_int64 *) pEnd);
 
  return (double) ((i64End - i64Start) / 10000000.0);
 
}
 

	
 
/*
 
** Print the timing results.
 
*/
 
static void endTimer(void){
 
  if( enableTimer && getProcessTimesAddr){
 
    FILETIME ftCreation, ftExit, ftKernelEnd, ftUserEnd;
 
    getProcessTimesAddr(hProcess, &ftCreation, &ftExit, &ftKernelEnd, &ftUserEnd);
 
    printf("CPU Time: user %f sys %f\n",
 
       timeDiff(&ftUserBegin, &ftUserEnd),
 
       timeDiff(&ftKernelBegin, &ftKernelEnd));
 
  }
 
}
 

	
 
#define BEGIN_TIMER beginTimer()
 
#define END_TIMER endTimer()
 
#define HAS_TIMER hasTimer()
 

	
 
#else
 
#define BEGIN_TIMER 
 
#define END_TIMER
 
#define HAS_TIMER 0
 
#endif
 

	
 
/*
 
** Used to prevent warnings about unused parameters
 
*/
 
#define UNUSED_PARAMETER(x) (void)(x)
 

	
 
/*
 
** If the following flag is set, then command execution stops
 
** at an error if we are not interactive.
 
*/
 
static int bail_on_error = 0;
 

	
 
/*
 
** Threat stdin as an interactive input if the following variable
 
** is true.  Otherwise, assume stdin is connected to a file or pipe.
 
*/
 
static int stdin_is_interactive = 1;
 

	
 
/*
 
** The following is the open SQLite database.  We make a pointer
 
** to this database a static variable so that it can be accessed
 
** by the SIGINT handler to interrupt database processing.
 
*/
 
static sqlite3 *db = 0;
 

	
 
/*
 
** True if an interrupt (Control-C) has been received.
 
*/
 
static volatile int seenInterrupt = 0;
 

	
 
/*
 
** This is the name of our program. It is set in main(), used
 
** in a number of other places, mostly for error messages.
 
*/
 
static char *Argv0;
 

	
 
/*
 
** Prompt strings. Initialized in main. Settable with
 
**   .prompt main continue
 
*/
 
static char mainPrompt[20];     /* First line prompt. default: "sqlite> "*/
 
static char continuePrompt[20]; /* Continuation prompt. default: "   ...> " */
 

	
 
/*
 
** Write I/O traces to the following stream.
 
*/
 
#ifdef SQLITE_ENABLE_IOTRACE
 
static FILE *iotrace = 0;
 
#endif
 

	
 
/*
 
** This routine works like printf in that its first argument is a
 
** format string and subsequent arguments are values to be substituted
 
** in place of % fields.  The result of formatting this string
 
** is written to iotrace.
 
*/
 
#ifdef SQLITE_ENABLE_IOTRACE
 
static void iotracePrintf(const char *zFormat, ...){
 
  va_list ap;
 
  char *z;
 
  if( iotrace==0 ) return;
 
  va_start(ap, zFormat);
 
  z = sqlite3_vmprintf(zFormat, ap);
 
  va_end(ap);
 
  fprintf(iotrace, "%s", z);
 
  sqlite3_free(z);
 
}
 
#endif
 

	
 

	
 
/*
 
** Determines if a string is a number of not.
 
*/
 
static int isNumber(const char *z, int *realnum){
 
  if( *z=='-' || *z=='+' ) z++;
 
  if( !IsDigit(*z) ){
 
    return 0;
 
  }
 
  z++;
 
  if( realnum ) *realnum = 0;
 
  while( IsDigit(*z) ){ z++; }
 
  if( *z=='.' ){
 
    z++;
 
    if( !IsDigit(*z) ) return 0;
 
    while( IsDigit(*z) ){ z++; }
 
    if( realnum ) *realnum = 1;
 
  }
 
  if( *z=='e' || *z=='E' ){
 
    z++;
 
    if( *z=='+' || *z=='-' ) z++;
 
    if( !IsDigit(*z) ) return 0;
 
    while( IsDigit(*z) ){ z++; }
 
    if( realnum ) *realnum = 1;
 
  }
 
  return *z==0;
 
}
 

	
 
/*
 
** A global char* and an SQL function to access its current value 
 
** from within an SQL statement. This program used to use the 
 
** sqlite_exec_printf() API to substitue a string into an SQL statement.
 
** The correct way to do this with sqlite3 is to use the bind API, but
 
** since the shell is built around the callback paradigm it would be a lot
 
** of work. Instead just use this hack, which is quite harmless.
 
*/
 
static const char *zShellStatic = 0;
 
static void shellstaticFunc(
 
  sqlite3_context *context,
 
  int argc,
 
  sqlite3_value **argv
 
){
 
  assert( 0==argc );
 
  assert( zShellStatic );
 
  UNUSED_PARAMETER(argc);
 
  UNUSED_PARAMETER(argv);
 
  sqlite3_result_text(context, zShellStatic, -1, SQLITE_STATIC);
 
}
 

	
 

	
 
/*
 
** This routine reads a line of text from FILE in, stores
 
** the text in memory obtained from malloc() and returns a pointer
 
** to the text.  NULL is returned at end of file, or if malloc()
 
** fails.
 
**
 
** The interface is like "readline" but no command-line editing
 
** is done.
 
*/
 
static char *local_getline(char *zPrompt, FILE *in){
 
  char *zLine;
 
  int nLine;
 
  int n;
 

	
 
  if( zPrompt && *zPrompt ){
 
    printf("%s",zPrompt);
 
    fflush(stdout);
 
  }
 
  nLine = 100;
 
  zLine = malloc( nLine );
 
  if( zLine==0 ) return 0;
 
  n = 0;
 
  while( 1 ){
 
    if( n+100>nLine ){
 
      nLine = nLine*2 + 100;
 
      zLine = realloc(zLine, nLine);
 
      if( zLine==0 ) return 0;
 
    }
 
    if( fgets(&zLine[n], nLine - n, in)==0 ){
 
      if( n==0 ){
 
        free(zLine);
 
        return 0;
 
      }
 
      zLine[n] = 0;
 
      break;
 
    }
 
    while( zLine[n] ){ n++; }
 
    if( n>0 && zLine[n-1]=='\n' ){
 
      n--;
 
      if( n>0 && zLine[n-1]=='\r' ) n--;
 
      zLine[n] = 0;
 
      break;
 
    }
 
  }
 
  zLine = realloc( zLine, n+1 );
 
  return zLine;
 
}
 

	
 
/*
 
** Retrieve a single line of input text.
 
**
 
** zPrior is a string of prior text retrieved.  If not the empty
 
** string, then issue a continuation prompt.
 
*/
 
static char *one_input_line(const char *zPrior, FILE *in){
 
  char *zPrompt;
 
  char *zResult;
 
  if( in!=0 ){
 
    return local_getline(0, in);
 
  }
 
  if( zPrior && zPrior[0] ){
 
    zPrompt = continuePrompt;
 
  }else{
 
    zPrompt = mainPrompt;
 
  }
 
  zResult = readline(zPrompt);
 
#if defined(HAVE_READLINE) && HAVE_READLINE==1
 
  if( zResult && *zResult ) add_history(zResult);
 
#endif
 
  return zResult;
 
}
 

	
 
struct previous_mode_data {
 
  int valid;        /* Is there legit data in here? */
 
  int mode;
 
  int showHeader;
 
  int colWidth[100];
 
};
 

	
 
/*
 
** An pointer to an instance of this structure is passed from
 
** the main program to the callback.  This is used to communicate
 
** state and mode information.
 
*/
 
struct callback_data {
 
  sqlite3 *db;           /* The database */
 
  int echoOn;            /* True to echo input commands */
 
  int statsOn;           /* True to display memory stats before each finalize */
 
  int cnt;               /* Number of records displayed so far */
 
  FILE *out;             /* Write results here */
 
  int nErr;              /* Number of errors seen */
 
  int mode;              /* An output mode setting */
 
  int writableSchema;    /* True if PRAGMA writable_schema=ON */
 
  int showHeader;        /* True to show column names in List or Column mode */
 
  char *zDestTable;      /* Name of destination table when MODE_Insert */
 
  char separator[20];    /* Separator character for MODE_List */
 
  int colWidth[100];     /* Requested width of each column when in column mode*/
 
  int actualWidth[100];  /* Actual width of each column */
 
  char nullvalue[20];    /* The text to print when a NULL comes back from
 
                         ** the database */
 
  struct previous_mode_data explainPrev;
 
                         /* Holds the mode information just before
 
                         ** .explain ON */
 
  char outfile[FILENAME_MAX]; /* Filename for *out */
 
  const char *zDbFilename;    /* name of the database file */
 
  const char *zVfs;           /* Name of VFS to use */
 
  sqlite3_stmt *pStmt;   /* Current statement if any. */
 
  FILE *pLog;            /* Write log output here */
 
};
 

	
 
/*
 
** These are the allowed modes.
 
*/
 
#define MODE_Line     0  /* One column per line.  Blank line between records */
 
#define MODE_Column   1  /* One record per line in neat columns */
 
#define MODE_List     2  /* One record per line with a separator */
 
#define MODE_Semi     3  /* Same as MODE_List but append ";" to each line */
 
#define MODE_Html     4  /* Generate an XHTML table */
 
#define MODE_Insert   5  /* Generate SQL "insert" statements */
 
#define MODE_Tcl      6  /* Generate ANSI-C or TCL quoted elements */
 
#define MODE_Csv      7  /* Quote strings, numbers are plain */
 
#define MODE_Explain  8  /* Like MODE_Column, but do not truncate data */
 

	
 
static const char *modeDescr[] = {
 
  "line",
 
  "column",
 
  "list",
 
  "semi",
 
  "html",
 
  "insert",
 
  "tcl",
 
  "csv",
 
  "explain",
 
};
 

	
 
/*
 
** Number of elements in an array
 
*/
 
#define ArraySize(X)  (int)(sizeof(X)/sizeof(X[0]))
 

	
 
/*
 
** Compute a string length that is limited to what can be stored in
 
** lower 30 bits of a 32-bit signed integer.
 
*/
 
static int strlen30(const char *z){
 
  const char *z2 = z;
 
  while( *z2 ){ z2++; }
 
  return 0x3fffffff & (int)(z2 - z);
 
}
 

	
 
/*
 
** A callback for the sqlite3_log() interface.
 
*/
 
static void shellLog(void *pArg, int iErrCode, const char *zMsg){
 
  struct callback_data *p = (struct callback_data*)pArg;
 
  if( p->pLog==0 ) return;
 
  fprintf(p->pLog, "(%d) %s\n", iErrCode, zMsg);
 
  fflush(p->pLog);
 
}
 

	
 
/*
 
** Output the given string as a hex-encoded blob (eg. X'1234' )
 
*/
 
static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){
 
  int i;
 
  char *zBlob = (char *)pBlob;
 
  fprintf(out,"X'");
 
  for(i=0; i<nBlob; i++){ fprintf(out,"%02x",zBlob[i]); }
 
  fprintf(out,"'");
 
}
 

	
 
/*
 
** Output the given string as a quoted string using SQL quoting conventions.
 
*/
 
static void output_quoted_string(FILE *out, const char *z){
 
  int i;
 
  int nSingle = 0;
 
  for(i=0; z[i]; i++){
 
    if( z[i]=='\'' ) nSingle++;
 
  }
 
  if( nSingle==0 ){
 
    fprintf(out,"'%s'",z);
 
  }else{
 
    fprintf(out,"'");
 
    while( *z ){
 
      for(i=0; z[i] && z[i]!='\''; i++){}
 
      if( i==0 ){
 
        fprintf(out,"''");
 
        z++;
 
      }else if( z[i]=='\'' ){
 
        fprintf(out,"%.*s''",i,z);
 
        z += i+1;
 
      }else{
 
        fprintf(out,"%s",z);
 
        break;
 
      }
 
    }
 
    fprintf(out,"'");
 
  }
 
}
 

	
 
/*
 
** Output the given string as a quoted according to C or TCL quoting rules.
 
*/
 
static void output_c_string(FILE *out, const char *z){
 
  unsigned int c;
 
  fputc('"', out);
 
  while( (c = *(z++))!=0 ){
 
    if( c=='\\' ){
 
      fputc(c, out);
 
      fputc(c, out);
 
    }else if( c=='\t' ){
 
      fputc('\\', out);
 
      fputc('t', out);
 
    }else if( c=='\n' ){
 
      fputc('\\', out);
 
      fputc('n', out);
 
    }else if( c=='\r' ){
 
      fputc('\\', out);
 
      fputc('r', out);
 
    }else if( !isprint(c) ){
 
      fprintf(out, "\\%03o", c&0xff);
 
    }else{
 
      fputc(c, out);
 
    }
 
  }
 
  fputc('"', out);
 
}
 

	
 
/*
 
** Output the given string with characters that are special to
 
** HTML escaped.
 
*/
 
static void output_html_string(FILE *out, const char *z){
 
  int i;
 
  while( *z ){
 
    for(i=0;   z[i] 
 
            && z[i]!='<' 
 
            && z[i]!='&' 
 
            && z[i]!='>' 
 
            && z[i]!='\"' 
 
            && z[i]!='\'';
 
        i++){}
 
    if( i>0 ){
 
      fprintf(out,"%.*s",i,z);
 
    }
 
    if( z[i]=='<' ){
 
      fprintf(out,"&lt;");
 
    }else if( z[i]=='&' ){
 
      fprintf(out,"&amp;");
 
    }else if( z[i]=='>' ){
 
      fprintf(out,"&gt;");
 
    }else if( z[i]=='\"' ){
 
      fprintf(out,"&quot;");
 
    }else if( z[i]=='\'' ){
 
      fprintf(out,"&#39;");
 
    }else{
 
      break;
 
    }
 
    z += i + 1;
 
  }
 
}
 

	
 
/*
 
** If a field contains any character identified by a 1 in the following
 
** array, then the string must be quoted for CSV.
 
*/
 
static const char needCsvQuote[] = {
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 0, 1, 0, 0, 0, 0, 1,   0, 0, 0, 0, 0, 0, 0, 0, 
 
  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
 
  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
 
  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
 
  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0, 
 
  0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 1, 
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
  1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,   
 
};
 

	
 
/*
 
** Output a single term of CSV.  Actually, p->separator is used for
 
** the separator, which may or may not be a comma.  p->nullvalue is
 
** the null value.  Strings are quoted using ANSI-C rules.  Numbers
 
** appear outside of quotes.
 
*/
 
static void output_csv(struct callback_data *p, const char *z, int bSep){
 
  FILE *out = p->out;
 
  if( z==0 ){
 
    fprintf(out,"%s",p->nullvalue);
 
  }else{
 
    int i;
 
    int nSep = strlen30(p->separator);
 
    for(i=0; z[i]; i++){
 
      if( needCsvQuote[((unsigned char*)z)[i]] 
 
         || (z[i]==p->separator[0] && 
 
             (nSep==1 || memcmp(z, p->separator, nSep)==0)) ){
 
        i = 0;
 
        break;
 
      }
 
    }
 
    if( i==0 ){
 
      putc('"', out);
 
      for(i=0; z[i]; i++){
 
        if( z[i]=='"' ) putc('"', out);
 
        putc(z[i], out);
 
      }
 
      putc('"', out);
 
    }else{
 
      fprintf(out, "%s", z);
 
    }
 
  }
 
  if( bSep ){
 
    fprintf(p->out, "%s", p->separator);
 
  }
 
}
 

	
 
#ifdef SIGINT
 
/*
 
** This routine runs when the user presses Ctrl-C
 
*/
 
static void interrupt_handler(int NotUsed){
 
  UNUSED_PARAMETER(NotUsed);
 
  seenInterrupt = 1;
 
  if( db ) sqlite3_interrupt(db);
 
}
 
#endif
 

	
 
/*
 
** This is the callback routine that the shell
 
** invokes for each row of a query result.
 
*/
 
static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int *aiType){
 
  int i;
 
  struct callback_data *p = (struct callback_data*)pArg;
 

	
 
  switch( p->mode ){
 
    case MODE_Line: {
 
      int w = 5;
 
      if( azArg==0 ) break;
 
      for(i=0; i<nArg; i++){
 
        int len = strlen30(azCol[i] ? azCol[i] : "");
 
        if( len>w ) w = len;
 
      }
 
      if( p->cnt++>0 ) fprintf(p->out,"\n");
 
      for(i=0; i<nArg; i++){
 
        fprintf(p->out,"%*s = %s\n", w, azCol[i],
 
                azArg[i] ? azArg[i] : p->nullvalue);
 
      }
 
      break;
 
    }
 
    case MODE_Explain:
 
    case MODE_Column: {
 
      if( p->cnt++==0 ){
 
        for(i=0; i<nArg; i++){
 
          int w, n;
 
          if( i<ArraySize(p->colWidth) ){
 
            w = p->colWidth[i];
 
          }else{
 
            w = 0;
 
          }
 
          if( w<=0 ){
 
            w = strlen30(azCol[i] ? azCol[i] : "");
 
            if( w<10 ) w = 10;
 
            n = strlen30(azArg && azArg[i] ? azArg[i] : p->nullvalue);
 
            if( w<n ) w = n;
 
          }
 
          if( i<ArraySize(p->actualWidth) ){
 
            p->actualWidth[i] = w;
 
          }
 
          if( p->showHeader ){
 
            fprintf(p->out,"%-*.*s%s",w,w,azCol[i], i==nArg-1 ? "\n": "  ");
 
          }
 
        }
 
        if( p->showHeader ){
 
          for(i=0; i<nArg; i++){
 
            int w;
 
            if( i<ArraySize(p->actualWidth) ){
 
               w = p->actualWidth[i];
 
            }else{
 
               w = 10;
 
            }
 
            fprintf(p->out,"%-*.*s%s",w,w,"-----------------------------------"
 
                   "----------------------------------------------------------",
 
                    i==nArg-1 ? "\n": "  ");
 
          }
 
        }
 
      }
 
      if( azArg==0 ) break;
 
      for(i=0; i<nArg; i++){
 
        int w;
 
        if( i<ArraySize(p->actualWidth) ){
 
           w = p->actualWidth[i];
 
        }else{
 
           w = 10;
 
        }
 
        if( p->mode==MODE_Explain && azArg[i] && 
 
           strlen30(azArg[i])>w ){
 
          w = strlen30(azArg[i]);
 
        }
 
        fprintf(p->out,"%-*.*s%s",w,w,
 
            azArg[i] ? azArg[i] : p->nullvalue, i==nArg-1 ? "\n": "  ");
 
      }
 
      break;
 
    }
 
    case MODE_Semi:
 
    case MODE_List: {
 
      if( p->cnt++==0 && p->showHeader ){
 
        for(i=0; i<nArg; i++){
 
          fprintf(p->out,"%s%s",azCol[i], i==nArg-1 ? "\n" : p->separator);
 
        }
 
      }
 
      if( azArg==0 ) break;
 
      for(i=0; i<nArg; i++){
 
        char *z = azArg[i];
 
        if( z==0 ) z = p->nullvalue;
 
        fprintf(p->out, "%s", z);
 
        if( i<nArg-1 ){
 
          fprintf(p->out, "%s", p->separator);
 
        }else if( p->mode==MODE_Semi ){
 
          fprintf(p->out, ";\n");
 
        }else{
 
          fprintf(p->out, "\n");
 
        }
 
      }
 
      break;
 
    }
 
    case MODE_Html: {
 
      if( p->cnt++==0 && p->showHeader ){
 
        fprintf(p->out,"<TR>");
 
        for(i=0; i<nArg; i++){
 
          fprintf(p->out,"<TH>");
 
          output_html_string(p->out, azCol[i]);
 
          fprintf(p->out,"</TH>\n");
 
        }
 
        fprintf(p->out,"</TR>\n");
 
      }
 
      if( azArg==0 ) break;
 
      fprintf(p->out,"<TR>");
 
      for(i=0; i<nArg; i++){
 
        fprintf(p->out,"<TD>");
 
        output_html_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
 
        fprintf(p->out,"</TD>\n");
 
      }
 
      fprintf(p->out,"</TR>\n");
 
      break;
 
    }
 
    case MODE_Tcl: {
 
      if( p->cnt++==0 && p->showHeader ){
 
        for(i=0; i<nArg; i++){
 
          output_c_string(p->out,azCol[i] ? azCol[i] : "");
 
          fprintf(p->out, "%s", p->separator);
 
        }
 
        fprintf(p->out,"\n");
 
      }
 
      if( azArg==0 ) break;
 
      for(i=0; i<nArg; i++){
 
        output_c_string(p->out, azArg[i] ? azArg[i] : p->nullvalue);
 
        fprintf(p->out, "%s", p->separator);
 
      }
 
      fprintf(p->out,"\n");
 
      break;
 
    }
 
    case MODE_Csv: {
 
      if( p->cnt++==0 && p->showHeader ){
 
        for(i=0; i<nArg; i++){
 
          output_csv(p, azCol[i] ? azCol[i] : "", i<nArg-1);
 
        }
 
        fprintf(p->out,"\n");
 
      }
 
      if( azArg==0 ) break;
 
      for(i=0; i<nArg; i++){
 
        output_csv(p, azArg[i], i<nArg-1);
 
      }
 
      fprintf(p->out,"\n");
 
      break;
 
    }
 
    case MODE_Insert: {
 
      p->cnt++;
 
      if( azArg==0 ) break;
 
      fprintf(p->out,"INSERT INTO %s VALUES(",p->zDestTable);
 
      for(i=0; i<nArg; i++){
 
        char *zSep = i>0 ? ",": "";
 
        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
 
          fprintf(p->out,"%sNULL",zSep);
 
        }else if( aiType && aiType[i]==SQLITE_TEXT ){
 
          if( zSep[0] ) fprintf(p->out,"%s",zSep);
 
          output_quoted_string(p->out, azArg[i]);
 
        }else if( aiType && (aiType[i]==SQLITE_INTEGER || aiType[i]==SQLITE_FLOAT) ){
 
          fprintf(p->out,"%s%s",zSep, azArg[i]);
 
        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
 
          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
 
          int nBlob = sqlite3_column_bytes(p->pStmt, i);
 
          if( zSep[0] ) fprintf(p->out,"%s",zSep);
 
          output_hex_blob(p->out, pBlob, nBlob);
 
        }else if( isNumber(azArg[i], 0) ){
 
          fprintf(p->out,"%s%s",zSep, azArg[i]);
 
        }else{
 
          if( zSep[0] ) fprintf(p->out,"%s",zSep);
 
          output_quoted_string(p->out, azArg[i]);
 
        }
 
      }
 
      fprintf(p->out,");\n");
 
      break;
 
    }
 
  }
 
  return 0;
 
}
 

	
 
/*
 
** This is the callback routine that the SQLite library
 
** invokes for each row of a query result.
 
*/
 
static int callback(void *pArg, int nArg, char **azArg, char **azCol){
 
  /* since we don't have type info, call the shell_callback with a NULL value */
 
  return shell_callback(pArg, nArg, azArg, azCol, NULL);
 
}
 

	
 
/*
 
** Set the destination table field of the callback_data structure to
 
** the name of the table given.  Escape any quote characters in the
 
** table name.
 
*/
 
static void set_table_name(struct callback_data *p, const char *zName){
 
  int i, n;
 
  int needQuote;
 
  char *z;
 

	
 
  if( p->zDestTable ){
 
    free(p->zDestTable);
 
    p->zDestTable = 0;
 
  }
 
  if( zName==0 ) return;
 
  needQuote = !isalpha((unsigned char)*zName) && *zName!='_';
 
  for(i=n=0; zName[i]; i++, n++){
 
    if( !isalnum((unsigned char)zName[i]) && zName[i]!='_' ){
 
      needQuote = 1;
 
      if( zName[i]=='\'' ) n++;
 
    }
 
  }
 
  if( needQuote ) n += 2;
 
  z = p->zDestTable = malloc( n+1 );
 
  if( z==0 ){
 
    fprintf(stderr,"Error: out of memory\n");
 
    exit(1);
 
  }
 
  n = 0;
 
  if( needQuote ) z[n++] = '\'';
 
  for(i=0; zName[i]; i++){
 
    z[n++] = zName[i];
 
    if( zName[i]=='\'' ) z[n++] = '\'';
 
  }
 
  if( needQuote ) z[n++] = '\'';
 
  z[n] = 0;
 
}
 

	
 
/* zIn is either a pointer to a NULL-terminated string in memory obtained
 
** from malloc(), or a NULL pointer. The string pointed to by zAppend is
 
** added to zIn, and the result returned in memory obtained from malloc().
 
** zIn, if it was not NULL, is freed.
 
**
 
** If the third argument, quote, is not '\0', then it is used as a 
 
** quote character for zAppend.
 
*/
 
static char *appendText(char *zIn, char const *zAppend, char quote){
 
  int len;
 
  int i;
 
  int nAppend = strlen30(zAppend);
 
  int nIn = (zIn?strlen30(zIn):0);
 

	
 
  len = nAppend+nIn+1;
 
  if( quote ){
 
    len += 2;
 
    for(i=0; i<nAppend; i++){
 
      if( zAppend[i]==quote ) len++;
 
    }
 
  }
 

	
 
  zIn = (char *)realloc(zIn, len);
 
  if( !zIn ){
 
    return 0;
 
  }
 

	
 
  if( quote ){
 
    char *zCsr = &zIn[nIn];
 
    *zCsr++ = quote;
 
    for(i=0; i<nAppend; i++){
 
      *zCsr++ = zAppend[i];
 
      if( zAppend[i]==quote ) *zCsr++ = quote;
 
    }
 
    *zCsr++ = quote;
 
    *zCsr++ = '\0';
 
    assert( (zCsr-zIn)==len );
 
  }else{
 
    memcpy(&zIn[nIn], zAppend, nAppend);
 
    zIn[len-1] = '\0';
 
  }
 

	
 
  return zIn;
 
}
 

	
 

	
 
/*
 
** Execute a query statement that has a single result column.  Print
 
** that result column on a line by itself with a semicolon terminator.
 
**
 
** This is used, for example, to show the schema of the database by
 
** querying the SQLITE_MASTER table.
 
*/
 
static int run_table_dump_query(
 
  struct callback_data *p, /* Query context */
 
  const char *zSelect,     /* SELECT statement to extract content */
 
  const char *zFirstRow    /* Print before first row, if not NULL */
 
){
 
  sqlite3_stmt *pSelect;
 
  int rc;
 
  rc = sqlite3_prepare(p->db, zSelect, -1, &pSelect, 0);
 
  if( rc!=SQLITE_OK || !pSelect ){
 
    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
 
    p->nErr++;
 
    return rc;
 
  }
 
  rc = sqlite3_step(pSelect);
 
  while( rc==SQLITE_ROW ){
 
    if( zFirstRow ){
 
      fprintf(p->out, "%s", zFirstRow);
 
      zFirstRow = 0;
 
    }
 
    fprintf(p->out, "%s;\n", sqlite3_column_text(pSelect, 0));
 
    rc = sqlite3_step(pSelect);
 
  }
 
  rc = sqlite3_finalize(pSelect);
 
  if( rc!=SQLITE_OK ){
 
    fprintf(p->out, "/**** ERROR: (%d) %s *****/\n", rc, sqlite3_errmsg(p->db));
 
    p->nErr++;
 
  }
 
  return rc;
 
}
 

	
 
/*
 
** Allocate space and save off current error string.
 
*/
 
static char *save_err_msg(
 
  sqlite3 *db            /* Database to query */
 
){
 
  int nErrMsg = 1+strlen30(sqlite3_errmsg(db));
 
  char *zErrMsg = sqlite3_malloc(nErrMsg);
 
  if( zErrMsg ){
 
    memcpy(zErrMsg, sqlite3_errmsg(db), nErrMsg);
 
  }
 
  return zErrMsg;
 
}
 

	
 
/*
 
** Display memory stats.
 
*/
 
static int display_stats(
 
  sqlite3 *db,                /* Database to query */
 
  struct callback_data *pArg, /* Pointer to struct callback_data */
 
  int bReset                  /* True to reset the stats */
 
){
 
  int iCur;
 
  int iHiwtr;
 

	
 
  if( pArg && pArg->out ){
 
    
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Memory Used:                         %d (max %d) bytes\n", iCur, iHiwtr);
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Number of Outstanding Allocations:   %d (max %d)\n", iCur, iHiwtr);
 
/*
 
** Not currently used by the CLI.
 
**    iHiwtr = iCur = -1;
 
**    sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &iCur, &iHiwtr, bReset);
 
**    fprintf(pArg->out, "Number of Pcache Pages Used:         %d (max %d) pages\n", iCur, iHiwtr);
 
*/
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Number of Pcache Overflow Bytes:     %d (max %d) bytes\n", iCur, iHiwtr);
 
/*
 
** Not currently used by the CLI.
 
**    iHiwtr = iCur = -1;
 
**    sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &iCur, &iHiwtr, bReset);
 
**    fprintf(pArg->out, "Number of Scratch Allocations Used:  %d (max %d)\n", iCur, iHiwtr);
 
*/
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Number of Scratch Overflow Bytes:    %d (max %d) bytes\n", iCur, iHiwtr);
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Largest Allocation:                  %d bytes\n", iHiwtr);
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Largest Pcache Allocation:           %d bytes\n", iHiwtr);
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Largest Scratch Allocation:          %d bytes\n", iHiwtr);
 
#ifdef YYTRACKMAXSTACKDEPTH
 
    iHiwtr = iCur = -1;
 
    sqlite3_status(SQLITE_STATUS_PARSER_STACK, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Deepest Parser Stack:                %d (max %d)\n", iCur, iHiwtr);
 
#endif
 
  }
 

	
 
  if( pArg && pArg->out && db ){
 
    iHiwtr = iCur = -1;
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Lookaside Slots Used:                %d (max %d)\n", iCur, iHiwtr);
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Successful lookaside attempts:       %d\n", iHiwtr);
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Lookaside failures due to size:      %d\n", iHiwtr);
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Lookaside failures due to OOM:       %d\n", iHiwtr);
 
    iHiwtr = iCur = -1;
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Pager Heap Usage:                    %d bytes\n", iCur);    iHiwtr = iCur = -1;
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHiwtr, 1);
 
    fprintf(pArg->out, "Page cache hits:                     %d\n", iCur);
 
    iHiwtr = iCur = -1;
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHiwtr, 1);
 
    fprintf(pArg->out, "Page cache misses:                   %d\n", iCur); 
 
    iHiwtr = iCur = -1;
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Schema Heap Usage:                   %d bytes\n", iCur); 
 
    iHiwtr = iCur = -1;
 
    sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHiwtr, bReset);
 
    fprintf(pArg->out, "Statement Heap/Lookaside Usage:      %d bytes\n", iCur); 
 
  }
 

	
 
  if( pArg && pArg->out && db && pArg->pStmt ){
 
    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_FULLSCAN_STEP, bReset);
 
    fprintf(pArg->out, "Fullscan Steps:                      %d\n", iCur);
 
    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_SORT, bReset);
 
    fprintf(pArg->out, "Sort Operations:                     %d\n", iCur);
 
    iCur = sqlite3_stmt_status(pArg->pStmt, SQLITE_STMTSTATUS_AUTOINDEX, bReset);
 
    fprintf(pArg->out, "Autoindex Inserts:                   %d\n", iCur);
 
  }
 

	
 
  return 0;
 
}
 

	
 
/*
 
** Execute a statement or set of statements.  Print 
 
** any result rows/columns depending on the current mode 
 
** set via the supplied callback.
 
**
 
** This is very similar to SQLite's built-in sqlite3_exec() 
 
** function except it takes a slightly different callback 
 
** and callback data argument.
 
*/
 
static int shell_exec(
 
  sqlite3 *db,                                /* An open database */
 
  const char *zSql,                           /* SQL to be evaluated */
 
  int (*xCallback)(void*,int,char**,char**,int*),   /* Callback function */
 
                                              /* (not the same as sqlite3_exec) */
 
  struct callback_data *pArg,                 /* Pointer to struct callback_data */
 
  char **pzErrMsg                             /* Error msg written here */
 
){
 
  sqlite3_stmt *pStmt = NULL;     /* Statement to execute. */
 
  int rc = SQLITE_OK;             /* Return Code */
 
  int rc2;
 
  const char *zLeftover;          /* Tail of unprocessed SQL */
 

	
 
  if( pzErrMsg ){
 
    *pzErrMsg = NULL;
 
  }
 

	
 
  while( zSql[0] && (SQLITE_OK == rc) ){
 
    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover);
 
    if( SQLITE_OK != rc ){
 
      if( pzErrMsg ){
 
        *pzErrMsg = save_err_msg(db);
 
      }
 
    }else{
 
      if( !pStmt ){
 
        /* this happens for a comment or white-space */
 
        zSql = zLeftover;
 
        while( IsSpace(zSql[0]) ) zSql++;
 
        continue;
 
      }
 

	
 
      /* save off the prepared statment handle and reset row count */
 
      if( pArg ){
 
        pArg->pStmt = pStmt;
 
        pArg->cnt = 0;
 
      }
 

	
 
      /* echo the sql statement if echo on */
 
      if( pArg && pArg->echoOn ){
 
        const char *zStmtSql = sqlite3_sql(pStmt);
 
        fprintf(pArg->out, "%s\n", zStmtSql ? zStmtSql : zSql);
 
      }
 

	
 
      /* Output TESTCTRL_EXPLAIN text of requested */
 
      if( pArg && pArg->mode==MODE_Explain ){
 
        const char *zExplain = 0;
 
        sqlite3_test_control(SQLITE_TESTCTRL_EXPLAIN_STMT, pStmt, &zExplain);
 
        if( zExplain && zExplain[0] ){
 
          fprintf(pArg->out, "%s", zExplain);
 
        }
 
      }
 

	
 
      /* perform the first step.  this will tell us if we
 
      ** have a result set or not and how wide it is.
 
      */
 
      rc = sqlite3_step(pStmt);
 
      /* if we have a result set... */
 
      if( SQLITE_ROW == rc ){
 
        /* if we have a callback... */
 
        if( xCallback ){
 
          /* allocate space for col name ptr, value ptr, and type */
 
          int nCol = sqlite3_column_count(pStmt);
 
          void *pData = sqlite3_malloc(3*nCol*sizeof(const char*) + 1);
 
          if( !pData ){
 
            rc = SQLITE_NOMEM;
 
          }else{
 
            char **azCols = (char **)pData;      /* Names of result columns */
 
            char **azVals = &azCols[nCol];       /* Results */
 
            int *aiTypes = (int *)&azVals[nCol]; /* Result types */
 
            int i;
 
            assert(sizeof(int) <= sizeof(char *)); 
 
            /* save off ptrs to column names */
 
            for(i=0; i<nCol; i++){
 
              azCols[i] = (char *)sqlite3_column_name(pStmt, i);
 
            }
 
            do{
 
              /* extract the data and data types */
 
              for(i=0; i<nCol; i++){
 
                azVals[i] = (char *)sqlite3_column_text(pStmt, i);
 
                aiTypes[i] = sqlite3_column_type(pStmt, i);
 
                if( !azVals[i] && (aiTypes[i]!=SQLITE_NULL) ){
 
                  rc = SQLITE_NOMEM;
 
                  break; /* from for */
 
                }
 
              } /* end for */
 

	
 
              /* if data and types extracted successfully... */
 
              if( SQLITE_ROW == rc ){ 
 
                /* call the supplied callback with the result row data */
 
                if( xCallback(pArg, nCol, azVals, azCols, aiTypes) ){
 
                  rc = SQLITE_ABORT;
 
                }else{
 
                  rc = sqlite3_step(pStmt);
 
                }
 
              }
 
            } while( SQLITE_ROW == rc );
 
            sqlite3_free(pData);
 
          }
 
        }else{
 
          do{
 
            rc = sqlite3_step(pStmt);
 
          } while( rc == SQLITE_ROW );
 
        }
 
      }
 

	
 
      /* print usage stats if stats on */
 
      if( pArg && pArg->statsOn ){
 
        display_stats(db, pArg, 0);
 
      }
 

	
 
      /* Finalize the statement just executed. If this fails, save a 
 
      ** copy of the error message. Otherwise, set zSql to point to the
 
      ** next statement to execute. */
 
      rc2 = sqlite3_finalize(pStmt);
 
      if( rc!=SQLITE_NOMEM ) rc = rc2;
 
      if( rc==SQLITE_OK ){
 
        zSql = zLeftover;
 
        while( IsSpace(zSql[0]) ) zSql++;
 
      }else if( pzErrMsg ){
 
        *pzErrMsg = save_err_msg(db);
 
      }
 

	
 
      /* clear saved stmt handle */
 
      if( pArg ){
 
        pArg->pStmt = NULL;
 
      }
 
    }
 
  } /* end while */
 

	
 
  return rc;
 
}
 

	
 

	
 
/*
 
** This is a different callback routine used for dumping the database.
 
** Each row received by this callback consists of a table name,
 
** the table type ("index" or "table") and SQL to create the table.
 
** This routine should print text sufficient to recreate the table.
 
*/
 
static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
 
  int rc;
 
  const char *zTable;
 
  const char *zType;
 
  const char *zSql;
 
  const char *zPrepStmt = 0;
 
  struct callback_data *p = (struct callback_data *)pArg;
 

	
 
  UNUSED_PARAMETER(azCol);
 
  if( nArg!=3 ) return 1;
 
  zTable = azArg[0];
 
  zType = azArg[1];
 
  zSql = azArg[2];
 
  
 
  if( strcmp(zTable, "sqlite_sequence")==0 ){
 
    zPrepStmt = "DELETE FROM sqlite_sequence;\n";
 
  }else if( strcmp(zTable, "sqlite_stat1")==0 ){
 
    fprintf(p->out, "ANALYZE sqlite_master;\n");
 
  }else if( strncmp(zTable, "sqlite_", 7)==0 ){
 
    return 0;
 
  }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
 
    char *zIns;
 
    if( !p->writableSchema ){
 
      fprintf(p->out, "PRAGMA writable_schema=ON;\n");
 
      p->writableSchema = 1;
 
    }
 
    zIns = sqlite3_mprintf(
 
       "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
 
       "VALUES('table','%q','%q',0,'%q');",
 
       zTable, zTable, zSql);
 
    fprintf(p->out, "%s\n", zIns);
 
    sqlite3_free(zIns);
 
    return 0;
 
  }else{
 
    fprintf(p->out, "%s;\n", zSql);
 
  }
 

	
 
  if( strcmp(zType, "table")==0 ){
 
    sqlite3_stmt *pTableInfo = 0;
 
    char *zSelect = 0;
 
    char *zTableInfo = 0;
 
    char *zTmp = 0;
 
    int nRow = 0;
 
   
 
    zTableInfo = appendText(zTableInfo, "PRAGMA table_info(", 0);
 
    zTableInfo = appendText(zTableInfo, zTable, '"');
 
    zTableInfo = appendText(zTableInfo, ");", 0);
 

	
 
    rc = sqlite3_prepare(p->db, zTableInfo, -1, &pTableInfo, 0);
 
    free(zTableInfo);
 
    if( rc!=SQLITE_OK || !pTableInfo ){
 
      return 1;
 
    }
 

	
 
    zSelect = appendText(zSelect, "SELECT 'INSERT INTO ' || ", 0);
 
    zTmp = appendText(zTmp, zTable, '"');
 
    if( zTmp ){
 
      zSelect = appendText(zSelect, zTmp, '\'');
 
    }
 
    zSelect = appendText(zSelect, " || ' VALUES(' || ", 0);
 
    rc = sqlite3_step(pTableInfo);
 
    while( rc==SQLITE_ROW ){
 
      const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1);
 
      zSelect = appendText(zSelect, "quote(", 0);
 
      zSelect = appendText(zSelect, zText, '"');
 
      rc = sqlite3_step(pTableInfo);
 
      if( rc==SQLITE_ROW ){
 
        zSelect = appendText(zSelect, ") || ',' || ", 0);
 
      }else{
 
        zSelect = appendText(zSelect, ") ", 0);
 
      }
 
      nRow++;
 
    }
 
    rc = sqlite3_finalize(pTableInfo);
 
    if( rc!=SQLITE_OK || nRow==0 ){
 
      free(zSelect);
 
      return 1;
 
    }
 
    zSelect = appendText(zSelect, "|| ')' FROM  ", 0);
 
    zSelect = appendText(zSelect, zTable, '"');
 

	
 
    rc = run_table_dump_query(p, zSelect, zPrepStmt);
 
    if( rc==SQLITE_CORRUPT ){
 
      zSelect = appendText(zSelect, " ORDER BY rowid DESC", 0);
 
      run_table_dump_query(p, zSelect, 0);
 
    }
 
    if( zSelect ) free(zSelect);
 
  }
 
  return 0;
 
}
 

	
 
/*
 
** Run zQuery.  Use dump_callback() as the callback routine so that
 
** the contents of the query are output as SQL statements.
 
**
 
** If we get a SQLITE_CORRUPT error, rerun the query after appending
 
** "ORDER BY rowid DESC" to the end.
 
*/
 
static int run_schema_dump_query(
 
  struct callback_data *p, 
 
  const char *zQuery
 
){
 
  int rc;
 
  char *zErr = 0;
 
  rc = sqlite3_exec(p->db, zQuery, dump_callback, p, &zErr);
 
  if( rc==SQLITE_CORRUPT ){
 
    char *zQ2;
 
    int len = strlen30(zQuery);
 
    fprintf(p->out, "/****** CORRUPTION ERROR *******/\n");
 
    if( zErr ){
 
      fprintf(p->out, "/****** %s ******/\n", zErr);
 
      sqlite3_free(zErr);
 
      zErr = 0;
 
    }
 
    zQ2 = malloc( len+100 );
 
    if( zQ2==0 ) return rc;
 
    sqlite3_snprintf(sizeof(zQ2), zQ2, "%s ORDER BY rowid DESC", zQuery);
 
    rc = sqlite3_exec(p->db, zQ2, dump_callback, p, &zErr);
 
    if( rc ){
 
      fprintf(p->out, "/****** ERROR: %s ******/\n", zErr);
 
    }else{
 
      rc = SQLITE_CORRUPT;
 
    }
 
    sqlite3_free(zErr);
 
    free(zQ2);
 
  }
 
  return rc;
 
}
 

	
 
/*
 
** Text of a help message
 
*/
 
static char zHelp[] =
 
  ".backup ?DB? FILE      Backup DB (default \"main\") to FILE\n"
 
  ".bail ON|OFF           Stop after hitting an error.  Default OFF\n"
 
  ".databases             List names and files of attached databases\n"
 
  ".dump ?TABLE? ...      Dump the database in an SQL text format\n"
 
  "                         If TABLE specified, only dump tables matching\n"
 
  "                         LIKE pattern TABLE.\n"
 
  ".echo ON|OFF           Turn command echo on or off\n"
 
  ".exit                  Exit this program\n"
 
  ".explain ?ON|OFF?      Turn output mode suitable for EXPLAIN on or off.\n"
 
  "                         With no args, it turns EXPLAIN on.\n"
 
  ".header(s) ON|OFF      Turn display of headers on or off\n"
 
  ".help                  Show this message\n"
 
  ".import FILE TABLE     Import data from FILE into TABLE\n"
 
  ".indices ?TABLE?       Show names of all indices\n"
 
  "                         If TABLE specified, only show indices for tables\n"
 
  "                         matching LIKE pattern TABLE.\n"
 
#ifdef SQLITE_ENABLE_IOTRACE
 
  ".iotrace FILE          Enable I/O diagnostic logging to FILE\n"
 
#endif
 
#ifndef SQLITE_OMIT_LOAD_EXTENSION
 
  ".load FILE ?ENTRY?     Load an extension library\n"
 
#endif
 
  ".log FILE|off          Turn logging on or off.  FILE can be stderr/stdout\n"
 
  ".mode MODE ?TABLE?     Set output mode where MODE is one of:\n"
 
  "                         csv      Comma-separated values\n"
 
  "                         column   Left-aligned columns.  (See .width)\n"
 
  "                         html     HTML <table> code\n"
 
  "                         insert   SQL insert statements for TABLE\n"
 
  "                         line     One value per line\n"
 
  "                         list     Values delimited by .separator string\n"
 
  "                         tabs     Tab-separated values\n"
 
  "                         tcl      TCL list elements\n"
 
  ".nullvalue STRING      Print STRING in place of NULL values\n"
 
  ".output FILENAME       Send output to FILENAME\n"
 
  ".output stdout         Send output to the screen\n"
 
  ".prompt MAIN CONTINUE  Replace the standard prompts\n"
 
  ".quit                  Exit this program\n"
 
  ".read FILENAME         Execute SQL in FILENAME\n"
 
  ".restore ?DB? FILE     Restore content of DB (default \"main\") from FILE\n"
 
  ".schema ?TABLE?        Show the CREATE statements\n"
 
  "                         If TABLE specified, only show tables matching\n"
 
  "                         LIKE pattern TABLE.\n"
 
  ".separator STRING      Change separator used by output mode and .import\n"
 
  ".show                  Show the current values for various settings\n"
 
  ".stats ON|OFF          Turn stats on or off\n"
 
  ".tables ?TABLE?        List names of tables\n"
 
  "                         If TABLE specified, only list tables matching\n"
 
  "                         LIKE pattern TABLE.\n"
 
  ".timeout MS            Try opening locked tables for MS milliseconds\n"
 
  ".vfsname ?AUX?         Print the name of the VFS stack\n"
 
  ".width NUM1 NUM2 ...   Set column widths for \"column\" mode\n"
 
;
 

	
 
static char zTimerHelp[] =
 
  ".timer ON|OFF          Turn the CPU timer measurement on or off\n"
 
;
 

	
 
/* Forward reference */
 
static int process_input(struct callback_data *p, FILE *in);
 

	
 
/*
 
** Make sure the database is open.  If it is not, then open it.  If
 
** the database fails to open, print an error message and exit.
 
*/
 
static void open_db(struct callback_data *p){
 
  if( p->db==0 ){
 
    sqlite3_open(p->zDbFilename, &p->db);
 
    db = p->db;
 
    if( db && sqlite3_errcode(db)==SQLITE_OK ){
 
      sqlite3_create_function(db, "shellstatic", 0, SQLITE_UTF8, 0,
 
          shellstaticFunc, 0, 0);
 
    }
 
    if( db==0 || SQLITE_OK!=sqlite3_errcode(db) ){
 
      fprintf(stderr,"Error: unable to open database \"%s\": %s\n", 
 
          p->zDbFilename, sqlite3_errmsg(db));
 
      exit(1);
 
    }
 
#ifndef SQLITE_OMIT_LOAD_EXTENSION
 
    sqlite3_enable_load_extension(p->db, 1);
 
#endif
 
  }
 
}
 

	
 
/*
 
** Do C-language style dequoting.
 
**
 
**    \t    -> tab
 
**    \n    -> newline
 
**    \r    -> carriage return
 
**    \NNN  -> ascii character NNN in octal
 
**    \\    -> backslash
 
*/
 
static void resolve_backslashes(char *z){
 
  int i, j;
 
  char c;
 
  for(i=j=0; (c = z[i])!=0; i++, j++){
 
    if( c=='\\' ){
 
      c = z[++i];
 
      if( c=='n' ){
 
        c = '\n';
 
      }else if( c=='t' ){
 
        c = '\t';
 
      }else if( c=='r' ){
 
        c = '\r';
 
      }else if( c>='0' && c<='7' ){
 
        c -= '0';
 
        if( z[i+1]>='0' && z[i+1]<='7' ){
 
          i++;
 
          c = (c<<3) + z[i] - '0';
 
          if( z[i+1]>='0' && z[i+1]<='7' ){
 
            i++;
 
            c = (c<<3) + z[i] - '0';
 
          }
 
        }
 
      }
 
    }
 
    z[j] = c;
 
  }
 
  z[j] = 0;
 
}
 

	
 
/*
 
** Interpret zArg as a boolean value.  Return either 0 or 1.
 
*/
 
static int booleanValue(char *zArg){
 
  int val = atoi(zArg);
 
  int j;
 
  for(j=0; zArg[j]; j++){
 
    zArg[j] = ToLower(zArg[j]);
 
  }
 
  if( strcmp(zArg,"on")==0 ){
 
    val = 1;
 
  }else if( strcmp(zArg,"yes")==0 ){
 
    val = 1;
 
  }
 
  return val;
 
}
 

	
 
/*
 
** If an input line begins with "." then invoke this routine to
 
** process that line.
 
**
 
** Return 1 on error, 2 to exit, and 0 otherwise.
 
*/
 
static int do_meta_command(char *zLine, struct callback_data *p){
 
  int i = 1;
 
  int nArg = 0;
 
  int n, c;
 
  int rc = 0;
 
  char *azArg[50];
 

	
 
  /* Parse the input line into tokens.
 
  */
 
  while( zLine[i] && nArg<ArraySize(azArg) ){
 
    while( IsSpace(zLine[i]) ){ i++; }
 
    if( zLine[i]==0 ) break;
 
    if( zLine[i]=='\'' || zLine[i]=='"' ){
 
      int delim = zLine[i++];
 
      azArg[nArg++] = &zLine[i];
 
      while( zLine[i] && zLine[i]!=delim ){ i++; }
 
      if( zLine[i]==delim ){
 
        zLine[i++] = 0;
 
      }
 
      if( delim=='"' ) resolve_backslashes(azArg[nArg-1]);
 
    }else{
 
      azArg[nArg++] = &zLine[i];
 
      while( zLine[i] && !IsSpace(zLine[i]) ){ i++; }
 
      if( zLine[i] ) zLine[i++] = 0;
 
      resolve_backslashes(azArg[nArg-1]);
 
    }
 
  }
 

	
 
  /* Process the input line.
 
  */
 
  if( nArg==0 ) return 0; /* no tokens, no error */
 
  n = strlen30(azArg[0]);
 
  c = azArg[0][0];
 
  if( c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0 && nArg>1 && nArg<4){
 
    const char *zDestFile;
 
    const char *zDb;
 
    sqlite3 *pDest;
 
    sqlite3_backup *pBackup;
 
    if( nArg==2 ){
 
      zDestFile = azArg[1];
 
      zDb = "main";
 
    }else{
 
      zDestFile = azArg[2];
 
      zDb = azArg[1];
 
    }
 
    rc = sqlite3_open(zDestFile, &pDest);
 
    if( rc!=SQLITE_OK ){
 
      fprintf(stderr, "Error: cannot open \"%s\"\n", zDestFile);
 
      sqlite3_close(pDest);
 
      return 1;
 
    }
 
    open_db(p);
 
    pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb);
 
    if( pBackup==0 ){
 
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
 
      sqlite3_close(pDest);
 
      return 1;
 
    }
 
    while(  (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){}
 
    sqlite3_backup_finish(pBackup);
 
    if( rc==SQLITE_DONE ){
 
      rc = 0;
 
    }else{
 
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(pDest));
 
      rc = 1;
 
    }
 
    sqlite3_close(pDest);
 
  }else
 

	
 
  if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 && nArg>1 && nArg<3 ){
 
    bail_on_error = booleanValue(azArg[1]);
 
  }else
 

	
 
  if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 && nArg==1 ){
 
    struct callback_data data;
 
    char *zErrMsg = 0;
 
    open_db(p);
 
    memcpy(&data, p, sizeof(data));
 
    data.showHeader = 1;
 
    data.mode = MODE_Column;
 
    data.colWidth[0] = 3;
 
    data.colWidth[1] = 15;
 
    data.colWidth[2] = 58;
 
    data.cnt = 0;
 
    sqlite3_exec(p->db, "PRAGMA database_list; ", callback, &data, &zErrMsg);
 
    if( zErrMsg ){
 
      fprintf(stderr,"Error: %s\n", zErrMsg);
 
      sqlite3_free(zErrMsg);
 
      rc = 1;
 
    }
 
  }else
 

	
 
  if( c=='d' && strncmp(azArg[0], "dump", n)==0 && nArg<3 ){
 
    open_db(p);
 
    /* When playing back a "dump", the content might appear in an order
 
    ** which causes immediate foreign key constraints to be violated.
 
    ** So disable foreign-key constraint enforcement to prevent problems. */
 
    fprintf(p->out, "PRAGMA foreign_keys=OFF;\n");
 
    fprintf(p->out, "BEGIN TRANSACTION;\n");
 
    p->writableSchema = 0;
 
    sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
 
    p->nErr = 0;
 
    if( nArg==1 ){
 
      run_schema_dump_query(p, 
 
        "SELECT name, type, sql FROM sqlite_master "
 
        "WHERE sql NOT NULL AND type=='table' AND name!='sqlite_sequence'"
 
      );
 
      run_schema_dump_query(p, 
 
        "SELECT name, type, sql FROM sqlite_master "
 
        "WHERE name=='sqlite_sequence'"
 
      );
 
      run_table_dump_query(p,
 
        "SELECT sql FROM sqlite_master "
 
        "WHERE sql NOT NULL AND type IN ('index','trigger','view')", 0
 
      );
 
    }else{
 
      int i;
 
      for(i=1; i<nArg; i++){
 
        zShellStatic = azArg[i];
 
        run_schema_dump_query(p,
 
          "SELECT name, type, sql FROM sqlite_master "
 
          "WHERE tbl_name LIKE shellstatic() AND type=='table'"
 
          "  AND sql NOT NULL");
 
        run_table_dump_query(p,
 
          "SELECT sql FROM sqlite_master "
 
          "WHERE sql NOT NULL"
 
          "  AND type IN ('index','trigger','view')"
 
          "  AND tbl_name LIKE shellstatic()", 0
 
        );
 
        zShellStatic = 0;
 
      }
 
    }
 
    if( p->writableSchema ){
 
      fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
 
      p->writableSchema = 0;
 
    }
 
    sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
 
    sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
 
    fprintf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
 
  }else
 

	
 
  if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 && nArg<3 ){
 
    p->echoOn = booleanValue(azArg[1]);
 
  }else
 

	
 
  if( c=='e' && strncmp(azArg[0], "exit", n)==0  && nArg==1 ){
 
    rc = 2;
 
  }else
 

	
 
  if( c=='e' && strncmp(azArg[0], "explain", n)==0 && nArg<3 ){
 
    int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
 
    if(val == 1) {
 
      if(!p->explainPrev.valid) {
 
        p->explainPrev.valid = 1;
 
        p->explainPrev.mode = p->mode;
 
        p->explainPrev.showHeader = p->showHeader;
 
        memcpy(p->explainPrev.colWidth,p->colWidth,sizeof(p->colWidth));
 
      }
 
      /* We could put this code under the !p->explainValid
 
      ** condition so that it does not execute if we are already in
 
      ** explain mode. However, always executing it allows us an easy
 
      ** was to reset to explain mode in case the user previously
 
      ** did an .explain followed by a .width, .mode or .header
 
      ** command.
 
      */
 
      p->mode = MODE_Explain;
 
      p->showHeader = 1;
 
      memset(p->colWidth,0,ArraySize(p->colWidth));
 
      p->colWidth[0] = 4;                  /* addr */
 
      p->colWidth[1] = 13;                 /* opcode */
 
      p->colWidth[2] = 4;                  /* P1 */
 
      p->colWidth[3] = 4;                  /* P2 */
 
      p->colWidth[4] = 4;                  /* P3 */
 
      p->colWidth[5] = 13;                 /* P4 */
 
      p->colWidth[6] = 2;                  /* P5 */
 
      p->colWidth[7] = 13;                  /* Comment */
 
    }else if (p->explainPrev.valid) {
 
      p->explainPrev.valid = 0;
 
      p->mode = p->explainPrev.mode;
 
      p->showHeader = p->explainPrev.showHeader;
 
      memcpy(p->colWidth,p->explainPrev.colWidth,sizeof(p->colWidth));
 
    }
 
  }else
 

	
 
  if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
 
                 strncmp(azArg[0], "headers", n)==0) && nArg>1 && nArg<3 ){
 
    p->showHeader = booleanValue(azArg[1]);
 
  }else
 

	
 
  if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
 
    fprintf(stderr,"%s",zHelp);
 
    if( HAS_TIMER ){
 
      fprintf(stderr,"%s",zTimerHelp);
 
    }
 
  }else
 

	
 
  if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){
 
    char *zTable = azArg[2];    /* Insert data into this table */
 
    char *zFile = azArg[1];     /* The file from which to extract data */
 
    sqlite3_stmt *pStmt = NULL; /* A statement */
 
    int nCol;                   /* Number of columns in the table */
 
    int nByte;                  /* Number of bytes in an SQL string */
 
    int i, j;                   /* Loop counters */
 
    int nSep;                   /* Number of bytes in p->separator[] */
 
    char *zSql;                 /* An SQL statement */
 
    char *zLine;                /* A single line of input from the file */
 
    char **azCol;               /* zLine[] broken up into columns */
 
    char *zCommit;              /* How to commit changes */   
 
    FILE *in;                   /* The input file */
 
    int lineno = 0;             /* Line number of input file */
 

	
 
    open_db(p);
 
    nSep = strlen30(p->separator);
 
    if( nSep==0 ){
 
      fprintf(stderr, "Error: non-null separator required for import\n");
 
      return 1;
 
    }
 
    zSql = sqlite3_mprintf("SELECT * FROM %s", zTable);
 
    if( zSql==0 ){
 
      fprintf(stderr, "Error: out of memory\n");
 
      return 1;
 
    }
 
    nByte = strlen30(zSql);
 
    rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
 
    sqlite3_free(zSql);
 
    if( rc ){
 
      if (pStmt) sqlite3_finalize(pStmt);
 
      fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
 
      return 1;
 
    }
 
    nCol = sqlite3_column_count(pStmt);
 
    sqlite3_finalize(pStmt);
 
    pStmt = 0;
 
    if( nCol==0 ) return 0; /* no columns, no error */
 
    zSql = malloc( nByte + 20 + nCol*2 );
 
    if( zSql==0 ){
 
      fprintf(stderr, "Error: out of memory\n");
 
      return 1;
 
    }
 
    sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zTable);
 
    j = strlen30(zSql);
 
    for(i=1; i<nCol; i++){
 
      zSql[j++] = ',';
 
      zSql[j++] = '?';
 
    }
 
    zSql[j++] = ')';
 
    zSql[j] = 0;
 
    rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0);
 
    free(zSql);
 
    if( rc ){
 
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
 
      if (pStmt) sqlite3_finalize(pStmt);
 
      return 1;
 
    }
 
    in = fopen(zFile, "rb");
 
    if( in==0 ){
 
      fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
 
      sqlite3_finalize(pStmt);
 
      return 1;
 
    }
 
    azCol = malloc( sizeof(azCol[0])*(nCol+1) );
 
    if( azCol==0 ){
 
      fprintf(stderr, "Error: out of memory\n");
 
      fclose(in);
 
      sqlite3_finalize(pStmt);
 
      return 1;
 
    }
 
    sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
 
    zCommit = "COMMIT";
 
    while( (zLine = local_getline(0, in))!=0 ){
 
      char *z;
 
      lineno++;
 
      azCol[0] = zLine;
 
      for(i=0, z=zLine; *z && *z!='\n' && *z!='\r'; z++){
 
        if( *z==p->separator[0] && strncmp(z, p->separator, nSep)==0 ){
 
          *z = 0;
 
          i++;
 
          if( i<nCol ){
 
            azCol[i] = &z[nSep];
 
            z += nSep-1;
 
          }
 
        }
 
      } /* end for */
 
      *z = 0;
 
      if( i+1!=nCol ){
 
        fprintf(stderr,
 
                "Error: %s line %d: expected %d columns of data but found %d\n",
 
                zFile, lineno, nCol, i+1);
 
        zCommit = "ROLLBACK";
 
        free(zLine);
 
        rc = 1;
 
        break; /* from while */
 
      }
 
      for(i=0; i<nCol; i++){
 
        sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
 
      }
 
      sqlite3_step(pStmt);
 
      rc = sqlite3_reset(pStmt);
 
      free(zLine);
 
      if( rc!=SQLITE_OK ){
 
        fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
 
        zCommit = "ROLLBACK";
 
        rc = 1;
 
        break; /* from while */
 
      }
 
    } /* end while */
 
    free(azCol);
 
    fclose(in);
 
    sqlite3_finalize(pStmt);
 
    sqlite3_exec(p->db, zCommit, 0, 0, 0);
 
  }else
 

	
 
  if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){
 
    struct callback_data data;
 
    char *zErrMsg = 0;
 
    open_db(p);
 
    memcpy(&data, p, sizeof(data));
 
    data.showHeader = 0;
 
    data.mode = MODE_List;
 
    if( nArg==1 ){
 
      rc = sqlite3_exec(p->db,
 
        "SELECT name FROM sqlite_master "
 
        "WHERE type='index' AND name NOT LIKE 'sqlite_%' "
 
        "UNION ALL "
 
        "SELECT name FROM sqlite_temp_master "
 
        "WHERE type='index' "
 
        "ORDER BY 1",
 
        callback, &data, &zErrMsg
 
      );
 
    }else{
 
      zShellStatic = azArg[1];
 
      rc = sqlite3_exec(p->db,
 
        "SELECT name FROM sqlite_master "
 
        "WHERE type='index' AND tbl_name LIKE shellstatic() "
 
        "UNION ALL "
 
        "SELECT name FROM sqlite_temp_master "
 
        "WHERE type='index' AND tbl_name LIKE shellstatic() "
 
        "ORDER BY 1",
 
        callback, &data, &zErrMsg
 
      );
 
      zShellStatic = 0;
 
    }
 
    if( zErrMsg ){
 
      fprintf(stderr,"Error: %s\n", zErrMsg);
 
      sqlite3_free(zErrMsg);
 
      rc = 1;
 
    }else if( rc != SQLITE_OK ){
 
      fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
 
      rc = 1;
 
    }
 
  }else
 

	
 
#ifdef SQLITE_ENABLE_IOTRACE
 
  if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
 
    extern void (*sqlite3IoTrace)(const char*, ...);
 
    if( iotrace && iotrace!=stdout ) fclose(iotrace);
 
    iotrace = 0;
 
    if( nArg<2 ){
 
      sqlite3IoTrace = 0;
 
    }else if( strcmp(azArg[1], "-")==0 ){
 
      sqlite3IoTrace = iotracePrintf;
 
      iotrace = stdout;
 
    }else{
 
      iotrace = fopen(azArg[1], "w");
 
      if( iotrace==0 ){
 
        fprintf(stderr, "Error: cannot open \"%s\"\n", azArg[1]);
 
        sqlite3IoTrace = 0;
 
        rc = 1;
 
      }else{
 
        sqlite3IoTrace = iotracePrintf;
 
      }
 
    }
 
  }else
 
#endif
 

	
 
#ifndef SQLITE_OMIT_LOAD_EXTENSION
 
  if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
 
    const char *zFile, *zProc;
 
    char *zErrMsg = 0;
 
    zFile = azArg[1];
 
    zProc = nArg>=3 ? azArg[2] : 0;
 
    open_db(p);
 
    rc = sqlite3_load_extension(p->db, zFile, zProc, &zErrMsg);
 
    if( rc!=SQLITE_OK ){
 
      fprintf(stderr, "Error: %s\n", zErrMsg);
 
      sqlite3_free(zErrMsg);
 
      rc = 1;
 
    }
 
  }else
 
#endif
 

	
 
  if( c=='l' && strncmp(azArg[0], "log", n)==0 && nArg>=2 ){
 
    const char *zFile = azArg[1];
 
    if( p->pLog && p->pLog!=stdout && p->pLog!=stderr ){
 
      fclose(p->pLog);
 
      p->pLog = 0;
 
    }
 
    if( strcmp(zFile,"stdout")==0 ){
 
      p->pLog = stdout;
 
    }else if( strcmp(zFile, "stderr")==0 ){
 
      p->pLog = stderr;
 
    }else if( strcmp(zFile, "off")==0 ){
 
      p->pLog = 0;
 
    }else{
 
      p->pLog = fopen(zFile, "w");
 
      if( p->pLog==0 ){
 
        fprintf(stderr, "Error: cannot open \"%s\"\n", zFile);
 
      }
 
    }
 
  }else
 

	
 
  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==2 ){
 
    int n2 = strlen30(azArg[1]);
 
    if( (n2==4 && strncmp(azArg[1],"line",n2)==0)
 
        ||
 
        (n2==5 && strncmp(azArg[1],"lines",n2)==0) ){
 
      p->mode = MODE_Line;
 
    }else if( (n2==6 && strncmp(azArg[1],"column",n2)==0)
 
              ||
 
              (n2==7 && strncmp(azArg[1],"columns",n2)==0) ){
 
      p->mode = MODE_Column;
 
    }else if( n2==4 && strncmp(azArg[1],"list",n2)==0 ){
 
      p->mode = MODE_List;
 
    }else if( n2==4 && strncmp(azArg[1],"html",n2)==0 ){
 
      p->mode = MODE_Html;
 
    }else if( n2==3 && strncmp(azArg[1],"tcl",n2)==0 ){
 
      p->mode = MODE_Tcl;
 
    }else if( n2==3 && strncmp(azArg[1],"csv",n2)==0 ){
 
      p->mode = MODE_Csv;
 
      sqlite3_snprintf(sizeof(p->separator), p->separator, ",");
 
    }else if( n2==4 && strncmp(azArg[1],"tabs",n2)==0 ){
 
      p->mode = MODE_List;
 
      sqlite3_snprintf(sizeof(p->separator), p->separator, "\t");
 
    }else if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
 
      p->mode = MODE_Insert;
 
      set_table_name(p, "table");
 
    }else {
 
      fprintf(stderr,"Error: mode should be one of: "
 
         "column csv html insert line list tabs tcl\n");
 
      rc = 1;
 
    }
 
  }else
 

	
 
  if( c=='m' && strncmp(azArg[0], "mode", n)==0 && nArg==3 ){
 
    int n2 = strlen30(azArg[1]);
 
    if( n2==6 && strncmp(azArg[1],"insert",n2)==0 ){
 
      p->mode = MODE_Insert;
 
      set_table_name(p, azArg[2]);
 
    }else {
 
      fprintf(stderr, "Error: invalid arguments: "
 
        " \"%s\". Enter \".help\" for help\n", azArg[2]);
 
      rc = 1;
 
    }
 
  }else
 

	
 
  if( c=='n' && strncmp(azArg[0], "nullvalue", n)==0 && nArg==2 ) {
 
    sqlite3_snprintf(sizeof(p->nullvalue), p->nullvalue,
 
                     "%.*s", (int)ArraySize(p->nullvalue)-1, azArg[1]);
 
  }else
 

	
 
  if( c=='o' && strncmp(azArg[0], "output", n)==0 && nArg==2 ){
 
    if( p->out!=stdout ){
 
      fclose(p->out);
 
    }
 
    if( strcmp(azArg[1],"stdout")==0 ){
 
      p->out = stdout;
 
      sqlite3_snprintf(sizeof(p->outfile), p->outfile, "stdout");
 
    }else{
 
      p->out = fopen(azArg[1], "wb");
 
      if( p->out==0 ){
 
        fprintf(stderr,"Error: cannot write to \"%s\"\n", azArg[1]);
 
        p->out = stdout;
 
        rc = 1;
 
      } else {
 
         sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", azArg[1]);
 
      }
 
    }
 
  }else
 

	
 
  if( c=='p' && strncmp(azArg[0], "prompt", n)==0 && (nArg==2 || nArg==3)){
 
    if( nArg >= 2) {
 
      strncpy(mainPrompt,azArg[1],(int)ArraySize(mainPrompt)-1);
 
    }
 
    if( nArg >= 3) {
 
      strncpy(continuePrompt,azArg[2],(int)ArraySize(continuePrompt)-1);
 
    }
 
  }else
 

	
 
  if( c=='q' && strncmp(azArg[0], "quit", n)==0 && nArg==1 ){
 
    rc = 2;
 
  }else
 

	
 
  if( c=='r' && n>=3 && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
 
    FILE *alt = fopen(azArg[1], "rb");
 
    if( alt==0 ){
 
      fprintf(stderr,"Error: cannot open \"%s\"\n", azArg[1]);
 
      rc = 1;
 
    }else{
 
      rc = process_input(p, alt);
 
      fclose(alt);
 
    }
 
  }else
 

	
 
  if( c=='r' && n>=3 && strncmp(azArg[0], "restore", n)==0 && nArg>1 && nArg<4){
 
    const char *zSrcFile;
 
    const char *zDb;
 
    sqlite3 *pSrc;
 
    sqlite3_backup *pBackup;
 
    int nTimeout = 0;
 

	
 
    if( nArg==2 ){
 
      zSrcFile = azArg[1];
 
      zDb = "main";
 
    }else{
 
      zSrcFile = azArg[2];
 
      zDb = azArg[1];
 
    }
 
    rc = sqlite3_open(zSrcFile, &pSrc);
 
    if( rc!=SQLITE_OK ){
 
      fprintf(stderr, "Error: cannot open \"%s\"\n", zSrcFile);
 
      sqlite3_close(pSrc);
 
      return 1;
 
    }
 
    open_db(p);
 
    pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main");
 
    if( pBackup==0 ){
 
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
 
      sqlite3_close(pSrc);
 
      return 1;
 
    }
 
    while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK
 
          || rc==SQLITE_BUSY  ){
 
      if( rc==SQLITE_BUSY ){
 
        if( nTimeout++ >= 3 ) break;
 
        sqlite3_sleep(100);
 
      }
 
    }
 
    sqlite3_backup_finish(pBackup);
 
    if( rc==SQLITE_DONE ){
 
      rc = 0;
 
    }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
 
      fprintf(stderr, "Error: source database is busy\n");
 
      rc = 1;
 
    }else{
 
      fprintf(stderr, "Error: %s\n", sqlite3_errmsg(p->db));
 
      rc = 1;
 
    }
 
    sqlite3_close(pSrc);
 
  }else
 

	
 
  if( c=='s' && strncmp(azArg[0], "schema", n)==0 && nArg<3 ){
 
    struct callback_data data;
 
    char *zErrMsg = 0;
 
    open_db(p);
 
    memcpy(&data, p, sizeof(data));
 
    data.showHeader = 0;
 
    data.mode = MODE_Semi;
 
    if( nArg>1 ){
 
      int i;
 
      for(i=0; azArg[1][i]; i++) azArg[1][i] = ToLower(azArg[1][i]);
 
      if( strcmp(azArg[1],"sqlite_master")==0 ){
 
        char *new_argv[2], *new_colv[2];
 
        new_argv[0] = "CREATE TABLE sqlite_master (\n"
 
                      "  type text,\n"
 
                      "  name text,\n"
 
                      "  tbl_name text,\n"
 
                      "  rootpage integer,\n"
 
                      "  sql text\n"
 
                      ")";
 
        new_argv[1] = 0;
 
        new_colv[0] = "sql";
 
        new_colv[1] = 0;
 
        callback(&data, 1, new_argv, new_colv);
 
        rc = SQLITE_OK;
 
      }else if( strcmp(azArg[1],"sqlite_temp_master")==0 ){
 
        char *new_argv[2], *new_colv[2];
 
        new_argv[0] = "CREATE TEMP TABLE sqlite_temp_master (\n"
 
                      "  type text,\n"
 
                      "  name text,\n"
 
                      "  tbl_name text,\n"
 
                      "  rootpage integer,\n"
 
                      "  sql text\n"
 
                      ")";
 
        new_argv[1] = 0;
 
        new_colv[0] = "sql";
 
        new_colv[1] = 0;
 
        callback(&data, 1, new_argv, new_colv);
 
        rc = SQLITE_OK;
 
      }else{
 
        zShellStatic = azArg[1];
 
        rc = sqlite3_exec(p->db,
 
          "SELECT sql FROM "
 
          "  (SELECT sql sql, type type, tbl_name tbl_name, name name"
 
          "     FROM sqlite_master UNION ALL"
 
          "   SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
 
          "WHERE lower(tbl_name) LIKE shellstatic()"
 
          "  AND type!='meta' AND sql NOTNULL "
 
          "ORDER BY substr(type,2,1), name",
 
          callback, &data, &zErrMsg);
 
        zShellStatic = 0;
 
      }
 
    }else{
 
      rc = sqlite3_exec(p->db,
 
         "SELECT sql FROM "
 
         "  (SELECT sql sql, type type, tbl_name tbl_name, name name"
 
         "     FROM sqlite_master UNION ALL"
 
         "   SELECT sql, type, tbl_name, name FROM sqlite_temp_master) "
 
         "WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
 
         "ORDER BY substr(type,2,1), name",
 
         callback, &data, &zErrMsg
 
      );
 
    }
 
    if( zErrMsg ){
 
      fprintf(stderr,"Error: %s\n", zErrMsg);
 
      sqlite3_free(zErrMsg);
 
      rc = 1;
 
    }else if( rc != SQLITE_OK ){
 
      fprintf(stderr,"Error: querying schema information\n");
 
      rc = 1;
 
    }else{
 
      rc = 0;
 
    }
 
  }else
 

	
 
  if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){
 
    sqlite3_snprintf(sizeof(p->separator), p->separator,
 
                     "%.*s", (int)sizeof(p->separator)-1, azArg[1]);
 
  }else
 

	
 
  if( c=='s' && strncmp(azArg[0], "show", n)==0 && nArg==1 ){
 
    int i;
 
    fprintf(p->out,"%9.9s: %s\n","echo", p->echoOn ? "on" : "off");
 
    fprintf(p->out,"%9.9s: %s\n","explain", p->explainPrev.valid ? "on" :"off");
 
    fprintf(p->out,"%9.9s: %s\n","headers", p->showHeader ? "on" : "off");
 
    fprintf(p->out,"%9.9s: %s\n","mode", modeDescr[p->mode]);
 
    fprintf(p->out,"%9.9s: ", "nullvalue");
 
      output_c_string(p->out, p->nullvalue);
 
      fprintf(p->out, "\n");
 
    fprintf(p->out,"%9.9s: %s\n","output",
 
            strlen30(p->outfile) ? p->outfile : "stdout");
 
    fprintf(p->out,"%9.9s: ", "separator");
 
      output_c_string(p->out, p->separator);
 
      fprintf(p->out, "\n");
 
    fprintf(p->out,"%9.9s: %s\n","stats", p->statsOn ? "on" : "off");
 
    fprintf(p->out,"%9.9s: ","width");
 
    for (i=0;i<(int)ArraySize(p->colWidth) && p->colWidth[i] != 0;i++) {
 
      fprintf(p->out,"%d ",p->colWidth[i]);
 
    }
 
    fprintf(p->out,"\n");
 
  }else
 

	
 
  if( c=='s' && strncmp(azArg[0], "stats", n)==0 && nArg>1 && nArg<3 ){
 
    p->statsOn = booleanValue(azArg[1]);
 
  }else
 

	
 
  if( c=='t' && n>1 && strncmp(azArg[0], "tables", n)==0 && nArg<3 ){
 
    char **azResult;
 
    int nRow;
 
    char *zErrMsg;
 
    open_db(p);
 
    if( nArg==1 ){
 
      rc = sqlite3_get_table(p->db,
 
        "SELECT name FROM sqlite_master "
 
        "WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' "
 
        "UNION ALL "
 
        "SELECT name FROM sqlite_temp_master "
 
        "WHERE type IN ('table','view') "
 
        "ORDER BY 1",
 
        &azResult, &nRow, 0, &zErrMsg
 
      );
 
    }else{
 
      zShellStatic = azArg[1];
 
      rc = sqlite3_get_table(p->db,
 
        "SELECT name FROM sqlite_master "
 
        "WHERE type IN ('table','view') AND name LIKE shellstatic() "
 
        "UNION ALL "
 
        "SELECT name FROM sqlite_temp_master "
 
        "WHERE type IN ('table','view') AND name LIKE shellstatic() "
 
        "ORDER BY 1",
 
        &azResult, &nRow, 0, &zErrMsg
 
      );
 
      zShellStatic = 0;
 
    }
 
    if( zErrMsg ){
 
      fprintf(stderr,"Error: %s\n", zErrMsg);
 
      sqlite3_free(zErrMsg);
 
      rc = 1;
 
    }else if( rc != SQLITE_OK ){
 
      fprintf(stderr,"Error: querying sqlite_master and sqlite_temp_master\n");
 
      rc = 1;
 
    }else{
 
      int len, maxlen = 0;
 
      int i, j;
 
      int nPrintCol, nPrintRow;
 
      for(i=1; i<=nRow; i++){
 
        if( azResult[i]==0 ) continue;
 
        len = strlen30(azResult[i]);
 
        if( len>maxlen ) maxlen = len;
 
      }
 
      nPrintCol = 80/(maxlen+2);
 
      if( nPrintCol<1 ) nPrintCol = 1;
 
      nPrintRow = (nRow + nPrintCol - 1)/nPrintCol;
 
      for(i=0; i<nPrintRow; i++){
 
        for(j=i+1; j<=nRow; j+=nPrintRow){
 
          char *zSp = j<=nPrintRow ? "" : "  ";
 
          printf("%s%-*s", zSp, maxlen, azResult[j] ? azResult[j] : "");
 
        }
 
        printf("\n");
 
      }
 
    }
 
    sqlite3_free_table(azResult);
 
  }else
 

	
 
  if( c=='t' && n>=8 && strncmp(azArg[0], "testctrl", n)==0 && nArg>=2 ){
 
    static const struct {
 
       const char *zCtrlName;   /* Name of a test-control option */
 
       int ctrlCode;            /* Integer code for that option */
 
    } aCtrl[] = {
 
      { "prng_save",             SQLITE_TESTCTRL_PRNG_SAVE              },
 
      { "prng_restore",          SQLITE_TESTCTRL_PRNG_RESTORE           },
 
      { "prng_reset",            SQLITE_TESTCTRL_PRNG_RESET             },
 
      { "bitvec_test",           SQLITE_TESTCTRL_BITVEC_TEST            },
 
      { "fault_install",         SQLITE_TESTCTRL_FAULT_INSTALL          },
 
      { "benign_malloc_hooks",   SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS    },
 
      { "pending_byte",          SQLITE_TESTCTRL_PENDING_BYTE           },
 
      { "assert",                SQLITE_TESTCTRL_ASSERT                 },
 
      { "always",                SQLITE_TESTCTRL_ALWAYS                 },
 
      { "reserve",               SQLITE_TESTCTRL_RESERVE                },
 
      { "optimizations",         SQLITE_TESTCTRL_OPTIMIZATIONS          },
 
      { "iskeyword",             SQLITE_TESTCTRL_ISKEYWORD              },
 
      { "scratchmalloc",         SQLITE_TESTCTRL_SCRATCHMALLOC          },
 
    };
 
    int testctrl = -1;
 
    int rc = 0;
 
    int i, n;
 
    open_db(p);
 

	
 
    /* convert testctrl text option to value. allow any unique prefix
 
    ** of the option name, or a numerical value. */
 
    n = strlen30(azArg[1]);
 
    for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){
 
      if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){
 
        if( testctrl<0 ){
 
          testctrl = aCtrl[i].ctrlCode;
 
        }else{
 
          fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[1]);
 
          testctrl = -1;
 
          break;
 
        }
 
      }
 
    }
 
    if( testctrl<0 ) testctrl = atoi(azArg[1]);
 
    if( (testctrl<SQLITE_TESTCTRL_FIRST) || (testctrl>SQLITE_TESTCTRL_LAST) ){
 
      fprintf(stderr,"Error: invalid testctrl option: %s\n", azArg[1]);
 
    }else{
 
      switch(testctrl){
 

	
 
        /* sqlite3_test_control(int, db, int) */
 
        case SQLITE_TESTCTRL_OPTIMIZATIONS:
 
        case SQLITE_TESTCTRL_RESERVE:             
 
          if( nArg==3 ){
 
            int opt = (int)strtol(azArg[2], 0, 0);        
 
            rc = sqlite3_test_control(testctrl, p->db, opt);
 
            printf("%d (0x%08x)\n", rc, rc);
 
          } else {
 
            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
 
                    azArg[1]);
 
          }
 
          break;
 

	
 
        /* sqlite3_test_control(int) */
 
        case SQLITE_TESTCTRL_PRNG_SAVE:           
 
        case SQLITE_TESTCTRL_PRNG_RESTORE:        
 
        case SQLITE_TESTCTRL_PRNG_RESET:
 
          if( nArg==2 ){
 
            rc = sqlite3_test_control(testctrl);
 
            printf("%d (0x%08x)\n", rc, rc);
 
          } else {
 
            fprintf(stderr,"Error: testctrl %s takes no options\n", azArg[1]);
 
          }
 
          break;
 

	
 
        /* sqlite3_test_control(int, uint) */
 
        case SQLITE_TESTCTRL_PENDING_BYTE:        
 
          if( nArg==3 ){
 
            unsigned int opt = (unsigned int)atoi(azArg[2]);        
 
            rc = sqlite3_test_control(testctrl, opt);
 
            printf("%d (0x%08x)\n", rc, rc);
 
          } else {
 
            fprintf(stderr,"Error: testctrl %s takes a single unsigned"
 
                           " int option\n", azArg[1]);
 
          }
 
          break;
 
          
 
        /* sqlite3_test_control(int, int) */
 
        case SQLITE_TESTCTRL_ASSERT:              
 
        case SQLITE_TESTCTRL_ALWAYS:              
 
          if( nArg==3 ){
 
            int opt = atoi(azArg[2]);        
 
            rc = sqlite3_test_control(testctrl, opt);
 
            printf("%d (0x%08x)\n", rc, rc);
 
          } else {
 
            fprintf(stderr,"Error: testctrl %s takes a single int option\n",
 
                            azArg[1]);
 
          }
 
          break;
 

	
 
        /* sqlite3_test_control(int, char *) */
 
#ifdef SQLITE_N_KEYWORD
 
        case SQLITE_TESTCTRL_ISKEYWORD:           
 
          if( nArg==3 ){
 
            const char *opt = azArg[2];        
 
            rc = sqlite3_test_control(testctrl, opt);
 
            printf("%d (0x%08x)\n", rc, rc);
 
          } else {
 
            fprintf(stderr,"Error: testctrl %s takes a single char * option\n",
 
                            azArg[1]);
 
          }
 
          break;
 
#endif
 

	
 
        case SQLITE_TESTCTRL_BITVEC_TEST:         
 
        case SQLITE_TESTCTRL_FAULT_INSTALL:       
 
        case SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS: 
 
        case SQLITE_TESTCTRL_SCRATCHMALLOC:       
 
        default:
 
          fprintf(stderr,"Error: CLI support for testctrl %s not implemented\n",
 
                  azArg[1]);
 
          break;
 
      }
 
    }
 
  }else
 

	
 
  if( c=='t' && n>4 && strncmp(azArg[0], "timeout", n)==0 && nArg==2 ){
 
    open_db(p);
 
    sqlite3_busy_timeout(p->db, atoi(azArg[1]));
 
  }else
 
    
 
  if( HAS_TIMER && c=='t' && n>=5 && strncmp(azArg[0], "timer", n)==0
 
   && nArg==2
 
  ){
 
    enableTimer = booleanValue(azArg[1]);
 
  }else
 
  
 
  if( c=='v' && strncmp(azArg[0], "version", n)==0 ){
 
    printf("SQLite %s %s\n" /*extra-version-info*/,
 
        sqlite3_libversion(), sqlite3_sourceid());
 
  }else
 

	
 
  if( c=='v' && strncmp(azArg[0], "vfsname", n)==0 ){
 
    const char *zDbName = nArg==2 ? azArg[1] : "main";
 
    char *zVfsName = 0;
 
    if( p->db ){
 
      sqlite3_file_control(p->db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsName);
 
      if( zVfsName ){
 
        printf("%s\n", zVfsName);
 
        sqlite3_free(zVfsName);
 
      }
 
    }
 
  }else
 

	
 
  if( c=='w' && strncmp(azArg[0], "width", n)==0 && nArg>1 ){
 
    int j;
 
    assert( nArg<=ArraySize(azArg) );
 
    for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
 
      p->colWidth[j-1] = atoi(azArg[j]);
 
    }
 
  }else
 

	
 
  {
 
    fprintf(stderr, "Error: unknown command or invalid arguments: "
 
      " \"%s\". Enter \".help\" for help\n", azArg[0]);
 
    rc = 1;
 
  }
 

	
 
  return rc;
 
}
 

	
 
/*
 
** Return TRUE if a semicolon occurs anywhere in the first N characters
 
** of string z[].
 
*/
 
static int _contains_semicolon(const char *z, int N){
 
  int i;
 
  for(i=0; i<N; i++){  if( z[i]==';' ) return 1; }
 
  return 0;
 
}
 

	
 
/*
 
** Test to see if a line consists entirely of whitespace.
 
*/
 
static int _all_whitespace(const char *z){
 
  for(; *z; z++){
 
    if( IsSpace(z[0]) ) continue;
 
    if( *z=='/' && z[1]=='*' ){
 
      z += 2;
 
      while( *z && (*z!='*' || z[1]!='/') ){ z++; }
 
      if( *z==0 ) return 0;
 
      z++;
 
      continue;
 
    }
 
    if( *z=='-' && z[1]=='-' ){
 
      z += 2;
 
      while( *z && *z!='\n' ){ z++; }
 
      if( *z==0 ) return 1;
 
      continue;
 
    }
 
    return 0;
 
  }
 
  return 1;
 
}
 

	
 
/*
 
** Return TRUE if the line typed in is an SQL command terminator other
 
** than a semi-colon.  The SQL Server style "go" command is understood
 
** as is the Oracle "/".
 
*/
 
static int _is_command_terminator(const char *zLine){
 
  while( IsSpace(zLine[0]) ){ zLine++; };
 
  if( zLine[0]=='/' && _all_whitespace(&zLine[1]) ){
 
    return 1;  /* Oracle */
 
  }
 
  if( ToLower(zLine[0])=='g' && ToLower(zLine[1])=='o'
 
         && _all_whitespace(&zLine[2]) ){
 
    return 1;  /* SQL Server */
 
  }
 
  return 0;
 
}
 

	
 
/*
 
** Return true if zSql is a complete SQL statement.  Return false if it
 
** ends in the middle of a string literal or C-style comment.
 
*/
 
static int _is_complete(char *zSql, int nSql){
 
  int rc;
 
  if( zSql==0 ) return 1;
 
  zSql[nSql] = ';';
 
  zSql[nSql+1] = 0;
 
  rc = sqlite3_complete(zSql);
 
  zSql[nSql] = 0;
 
  return rc;
 
}
 

	
 
/*
 
** Read input from *in and process it.  If *in==0 then input
 
** is interactive - the user is typing it it.  Otherwise, input
 
** is coming from a file or device.  A prompt is issued and history
 
** is saved only if input is interactive.  An interrupt signal will
 
** cause this routine to exit immediately, unless input is interactive.
 
**
 
** Return the number of errors.
 
*/
 
static int process_input(struct callback_data *p, FILE *in){
 
  char *zLine = 0;
 
  char *zSql = 0;
 
  int nSql = 0;
 
  int nSqlPrior = 0;
 
  char *zErrMsg;
 
  int rc;
 
  int errCnt = 0;
 
  int lineno = 0;
 
  int startline = 0;
 

	
 
  while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
 
    fflush(p->out);
 
    free(zLine);
 
    zLine = one_input_line(zSql, in);
 
    if( zLine==0 ){
 
      break;  /* We have reached EOF */
 
    }
 
    if( seenInterrupt ){
 
      if( in!=0 ) break;
 
      seenInterrupt = 0;
 
    }
 
    lineno++;
 
    if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
 
    if( zLine && zLine[0]=='.' && nSql==0 ){
 
      if( p->echoOn ) printf("%s\n", zLine);
 
      rc = do_meta_command(zLine, p);
 
      if( rc==2 ){ /* exit requested */
 
        break;
 
      }else if( rc ){
 
        errCnt++;
 
      }
 
      continue;
 
    }
 
    if( _is_command_terminator(zLine) && _is_complete(zSql, nSql) ){
 
      memcpy(zLine,";",2);
 
    }
 
    nSqlPrior = nSql;
 
    if( zSql==0 ){
 
      int i;
 
      for(i=0; zLine[i] && IsSpace(zLine[i]); i++){}
 
      if( zLine[i]!=0 ){
 
        nSql = strlen30(zLine);
 
        zSql = malloc( nSql+3 );
 
        if( zSql==0 ){
 
          fprintf(stderr, "Error: out of memory\n");
 
          exit(1);
 
        }
 
        memcpy(zSql, zLine, nSql+1);
 
        startline = lineno;
 
      }
 
    }else{
 
      int len = strlen30(zLine);
 
      zSql = realloc( zSql, nSql + len + 4 );
 
      if( zSql==0 ){
 
        fprintf(stderr,"Error: out of memory\n");
 
        exit(1);
 
      }
 
      zSql[nSql++] = '\n';
 
      memcpy(&zSql[nSql], zLine, len+1);
 
      nSql += len;
 
    }
 
    if( zSql && _contains_semicolon(&zSql[nSqlPrior], nSql-nSqlPrior)
 
                && sqlite3_complete(zSql) ){
 
      p->cnt = 0;
 
      open_db(p);
 
      BEGIN_TIMER;
 
      rc = shell_exec(p->db, zSql, shell_callback, p, &zErrMsg);
 
      END_TIMER;
 
      if( rc || zErrMsg ){
 
        char zPrefix[100];
 
        if( in!=0 || !stdin_is_interactive ){
 
          sqlite3_snprintf(sizeof(zPrefix), zPrefix, 
 
                           "Error: near line %d:", startline);
 
        }else{
 
          sqlite3_snprintf(sizeof(zPrefix), zPrefix, "Error:");
 
        }
 
        if( zErrMsg!=0 ){
 
          fprintf(stderr, "%s %s\n", zPrefix, zErrMsg);
 
          sqlite3_free(zErrMsg);
 
          zErrMsg = 0;
 
        }else{
 
          fprintf(stderr, "%s %s\n", zPrefix, sqlite3_errmsg(p->db));
 
        }
 
        errCnt++;
 
      }
 
      free(zSql);
 
      zSql = 0;
 
      nSql = 0;
 
    }
 
  }
 
  if( zSql ){
 
    if( !_all_whitespace(zSql) ){
 
      fprintf(stderr, "Error: incomplete SQL: %s\n", zSql);
 
    }
 
    free(zSql);
 
  }
 
  free(zLine);
 
  return errCnt;
 
}
 

	
 
/*
 
** Return a pathname which is the user's home directory.  A
 
** 0 return indicates an error of some kind.  Space to hold the
 
** resulting string is obtained from malloc().  The calling
 
** function should free the result.
 
*/
 
static char *find_home_dir(void){
 
  char *home_dir = NULL;
 

	
 
#if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(_WIN32_WCE) && !defined(__RTP__) && !defined(_WRS_KERNEL)
 
  struct passwd *pwent;
 
  uid_t uid = getuid();
 
  if( (pwent=getpwuid(uid)) != NULL) {
 
    home_dir = pwent->pw_dir;
 
  }
 
#endif
 

	
 
#if defined(_WIN32_WCE)
 
  /* Windows CE (arm-wince-mingw32ce-gcc) does not provide getenv()
 
   */
 
  home_dir = strdup("/");
 
#else
 

	
 
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
 
  if (!home_dir) {
 
    home_dir = getenv("USERPROFILE");
 
  }
 
#endif
 

	
 
  if (!home_dir) {
 
    home_dir = getenv("HOME");
 
  }
 

	
 
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
 
  if (!home_dir) {
 
    char *zDrive, *zPath;
 
    int n;
 
    zDrive = getenv("HOMEDRIVE");
 
    zPath = getenv("HOMEPATH");
 
    if( zDrive && zPath ){
 
      n = strlen30(zDrive) + strlen30(zPath) + 1;
 
      home_dir = malloc( n );
 
      if( home_dir==0 ) return 0;
 
      sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
 
      return home_dir;
 
    }
 
    home_dir = "c:\\";
 
  }
 
#endif
 

	
 
#endif /* !_WIN32_WCE */
 

	
 
  if( home_dir ){
 
    int n = strlen30(home_dir) + 1;
 
    char *z = malloc( n );
 
    if( z ) memcpy(z, home_dir, n);
 
    home_dir = z;
 
  }
 

	
 
  return home_dir;
 
}
 

	
 
/*
 
** Read input from the file given by sqliterc_override.  Or if that
 
** parameter is NULL, take input from ~/.sqliterc
 
**
 
** Returns the number of errors.
 
*/
 
static int process_sqliterc(
 
  struct callback_data *p,        /* Configuration data */
 
  const char *sqliterc_override   /* Name of config file. NULL to use default */
 
){
 
  char *home_dir = NULL;
 
  const char *sqliterc = sqliterc_override;
 
  char *zBuf = 0;
 
  FILE *in = NULL;
 
  int nBuf;
 
  int rc = 0;
 

	
 
  if (sqliterc == NULL) {
 
    home_dir = find_home_dir();
 
    if( home_dir==0 ){
 
#if !defined(__RTP__) && !defined(_WRS_KERNEL)
 
      fprintf(stderr,"%s: Error: cannot locate your home directory\n", Argv0);
 
#endif
 
      return 1;
 
    }
 
    nBuf = strlen30(home_dir) + 16;
 
    zBuf = malloc( nBuf );
 
    if( zBuf==0 ){
 
      fprintf(stderr,"%s: Error: out of memory\n",Argv0);
 
      return 1;
 
    }
 
    sqlite3_snprintf(nBuf, zBuf,"%s/.sqliterc",home_dir);
 
    free(home_dir);
 
    sqliterc = (const char*)zBuf;
 
  }
 
  in = fopen(sqliterc,"rb");
 
  if( in ){
 
    if( stdin_is_interactive ){
 
      fprintf(stderr,"-- Loading resources from %s\n",sqliterc);
 
    }
 
    rc = process_input(p,in);
 
    fclose(in);
 
  }
 
  free(zBuf);
 
  return rc;
 
}
 

	
 
/*
 
** Show available command line options
 
*/
 
static const char zOptions[] = 
 
  "   -help                show this message\n"
 
  "   -init filename       read/process named file\n"
 
  "   -echo                print commands before execution\n"
 
  "   -[no]header          turn headers on or off\n"
 
  "   -bail                stop after hitting an error\n"
 
  "   -interactive         force interactive I/O\n"
 
  "   -batch               force batch I/O\n"
 
  "   -column              set output mode to 'column'\n"
 
  "   -csv                 set output mode to 'csv'\n"
 
  "   -html                set output mode to HTML\n"
 
  "   -line                set output mode to 'line'\n"
 
  "   -list                set output mode to 'list'\n"
 
  "   -separator 'x'       set output field separator (|)\n"
 
  "   -stats               print memory stats before each finalize\n"
 
  "   -nullvalue 'text'    set text string for NULL values\n"
 
  "   -version             show SQLite version\n"
 
  "   -vfs NAME            use NAME as the default VFS\n"
 
#ifdef SQLITE_ENABLE_VFSTRACE
 
  "   -vfstrace            enable tracing of all VFS calls\n"
 
#endif
 
#ifdef SQLITE_ENABLE_MULTIPLEX
 
  "   -multiplex           enable the multiplexor VFS\n"
 
#endif
 
;
 
static void usage(int showDetail){
 
  fprintf(stderr,
 
      "Usage: %s [OPTIONS] FILENAME [SQL]\n"  
 
      "FILENAME is the name of an SQLite database. A new database is created\n"
 
      "if the file does not previously exist.\n", Argv0);
 
  if( showDetail ){
 
    fprintf(stderr, "OPTIONS include:\n%s", zOptions);
 
  }else{
 
    fprintf(stderr, "Use the -help option for additional information\n");
 
  }
 
  exit(1);
 
}
 

	
 
/*
 
** Initialize the state information in data
 
*/
 
static void main_init(struct callback_data *data) {
 
  memset(data, 0, sizeof(*data));
 
  data->mode = MODE_List;
 
  memcpy(data->separator,"|", 2);
 
  data->showHeader = 0;
 
  sqlite3_config(SQLITE_CONFIG_URI, 1);
 
  sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data);
 
  sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> ");
 
  sqlite3_snprintf(sizeof(continuePrompt), continuePrompt,"   ...> ");
 
  sqlite3_config(SQLITE_CONFIG_SINGLETHREAD);
 
}
 

	
 
int main(int argc, char **argv){
 
  char *zErrMsg = 0;
 
  struct callback_data data;
 
  const char *zInitFile = 0;
 
  char *zFirstCmd = 0;
 
  int i;
 
  int rc = 0;
 

	
 
  if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){
 
    fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n",
 
            sqlite3_sourceid(), SQLITE_SOURCE_ID);
 
    exit(1);
 
  }
 
  Argv0 = argv[0];
 
  main_init(&data);
 
  stdin_is_interactive = isatty(0);
 

	
 
  /* Make sure we have a valid signal handler early, before anything
 
  ** else is done.
 
  */
 
#ifdef SIGINT
 
  signal(SIGINT, interrupt_handler);
 
#endif
 

	
 
  /* Do an initial pass through the command-line argument to locate
 
  ** the name of the database file, the name of the initialization file,
 
  ** the size of the alternative malloc heap,
 
  ** and the first command to execute.
 
  */
 
  for(i=1; i<argc-1; i++){
 
    char *z;
 
    if( argv[i][0]!='-' ) break;
 
    z = argv[i];
 
    if( z[0]=='-' && z[1]=='-' ) z++;
 
    if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
 
      i++;
 
    }else if( strcmp(argv[i],"-init")==0 ){
 
      i++;
 
      zInitFile = argv[i];
 
    /* Need to check for batch mode here to so we can avoid printing
 
    ** informational messages (like from process_sqliterc) before 
 
    ** we do the actual processing of arguments later in a second pass.
 
    */
 
    }else if( strcmp(argv[i],"-batch")==0 ){
 
      stdin_is_interactive = 0;
 
    }else if( strcmp(argv[i],"-heap")==0 ){
 
#if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
 
      int j, c;
 
      const char *zSize;
 
      sqlite3_int64 szHeap;
 

	
 
      zSize = argv[++i];
 
      szHeap = atoi(zSize);
 
      for(j=0; (c = zSize[j])!=0; j++){
 
        if( c=='M' ){ szHeap *= 1000000; break; }
 
        if( c=='K' ){ szHeap *= 1000; break; }
 
        if( c=='G' ){ szHeap *= 1000000000; break; }
 
      }
 
      if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
 
      sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
 
#endif
 
#ifdef SQLITE_ENABLE_VFSTRACE
 
    }else if( strcmp(argv[i],"-vfstrace")==0 ){
 
      extern int vfstrace_register(
 
         const char *zTraceName,
 
         const char *zOldVfsName,
 
         int (*xOut)(const char*,void*),
 
         void *pOutArg,
 
         int makeDefault
 
      );
 
      vfstrace_register("trace",0,(int(*)(const char*,void*))fputs,stderr,1);
 
#endif
 
#ifdef SQLITE_ENABLE_MULTIPLEX
 
    }else if( strcmp(argv[i],"-multiplex")==0 ){
 
      extern int sqlite3_multiple_initialize(const char*,int);
 
      sqlite3_multiplex_initialize(0, 1);
 
#endif
 
    }else if( strcmp(argv[i],"-vfs")==0 ){
 
      sqlite3_vfs *pVfs = sqlite3_vfs_find(argv[++i]);
 
      if( pVfs ){
 
        sqlite3_vfs_register(pVfs, 1);
 
      }else{
 
        fprintf(stderr, "no such VFS: \"%s\"\n", argv[i]);
 
        exit(1);
 
      }
 
    }
 
  }
 
  if( i<argc ){
 
#if defined(SQLITE_OS_OS2) && SQLITE_OS_OS2
 
    data.zDbFilename = (const char *)convertCpPathToUtf8( argv[i++] );
 
#else
 
    data.zDbFilename = argv[i++];
 
#endif
 
  }else{
 
#ifndef SQLITE_OMIT_MEMORYDB
 
    data.zDbFilename = ":memory:";
 
#else
 
    data.zDbFilename = 0;
 
#endif
 
  }
 
  if( i<argc ){
 
    zFirstCmd = argv[i++];
 
  }
 
  if( i<argc ){
 
    fprintf(stderr,"%s: Error: too many options: \"%s\"\n", Argv0, argv[i]);
 
    fprintf(stderr,"Use -help for a list of options.\n");
 
    return 1;
 
  }
 
  data.out = stdout;
 

	
 
#ifdef SQLITE_OMIT_MEMORYDB
 
  if( data.zDbFilename==0 ){
 
    fprintf(stderr,"%s: Error: no database filename specified\n", Argv0);
 
    return 1;
 
  }
 
#endif
 

	
 
  /* Go ahead and open the database file if it already exists.  If the
 
  ** file does not exist, delay opening it.  This prevents empty database
 
  ** files from being created if a user mistypes the database name argument
 
  ** to the sqlite command-line tool.
 
  */
 
  if( access(data.zDbFilename, 0)==0 ){
 
    open_db(&data);
 
  }
 

	
 
  /* Process the initialization file if there is one.  If no -init option
 
  ** is given on the command line, look for a file named ~/.sqliterc and
 
  ** try to process it.
 
  */
 
  rc = process_sqliterc(&data,zInitFile);
 
  if( rc>0 ){
 
    return rc;
 
  }
 

	
 
  /* Make a second pass through the command-line argument and set
 
  ** options.  This second pass is delayed until after the initialization
 
  ** file is processed so that the command-line arguments will override
 
  ** settings in the initialization file.
 
  */
 
  for(i=1; i<argc && argv[i][0]=='-'; i++){
 
    char *z = argv[i];
 
    if( z[1]=='-' ){ z++; }
 
    if( strcmp(z,"-init")==0 ){
 
      i++;
 
    }else if( strcmp(z,"-html")==0 ){
 
      data.mode = MODE_Html;
 
    }else if( strcmp(z,"-list")==0 ){
 
      data.mode = MODE_List;
 
    }else if( strcmp(z,"-line")==0 ){
 
      data.mode = MODE_Line;
 
    }else if( strcmp(z,"-column")==0 ){
 
      data.mode = MODE_Column;
 
    }else if( strcmp(z,"-csv")==0 ){
 
      data.mode = MODE_Csv;
 
      memcpy(data.separator,",",2);
 
    }else if( strcmp(z,"-separator")==0 ){
 
      i++;
 
      if(i>=argc){
 
        fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
 
        fprintf(stderr,"Use -help for a list of options.\n");
 
        return 1;
 
      }
 
      sqlite3_snprintf(sizeof(data.separator), data.separator,
 
                       "%.*s",(int)sizeof(data.separator)-1,argv[i]);
 
    }else if( strcmp(z,"-nullvalue")==0 ){
 
      i++;
 
      if(i>=argc){
 
        fprintf(stderr,"%s: Error: missing argument for option: %s\n", Argv0, z);
 
        fprintf(stderr,"Use -help for a list of options.\n");
 
        return 1;
 
      }
 
      sqlite3_snprintf(sizeof(data.nullvalue), data.nullvalue,
 
                       "%.*s",(int)sizeof(data.nullvalue)-1,argv[i]);
 
    }else if( strcmp(z,"-header")==0 ){
 
      data.showHeader = 1;
 
    }else if( strcmp(z,"-noheader")==0 ){
 
      data.showHeader = 0;
 
    }else if( strcmp(z,"-echo")==0 ){
 
      data.echoOn = 1;
 
    }else if( strcmp(z,"-stats")==0 ){
 
      data.statsOn = 1;
 
    }else if( strcmp(z,"-bail")==0 ){
 
      bail_on_error = 1;
 
    }else if( strcmp(z,"-version")==0 ){
 
      printf("%s %s\n", sqlite3_libversion(), sqlite3_sourceid());
 
      return 0;
 
    }else if( strcmp(z,"-interactive")==0 ){
 
      stdin_is_interactive = 1;
 
    }else if( strcmp(z,"-batch")==0 ){
 
      stdin_is_interactive = 0;
 
    }else if( strcmp(z,"-heap")==0 ){
 
      i++;
 
    }else if( strcmp(z,"-vfs")==0 ){
 
      i++;
 
#ifdef SQLITE_ENABLE_VFSTRACE
 
    }else if( strcmp(z,"-vfstrace")==0 ){
 
      i++;
 
#endif
 
#ifdef SQLITE_ENABLE_MULTIPLEX
 
    }else if( strcmp(z,"-multiplex")==0 ){
 
      i++;
 
#endif
 
    }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
 
      usage(1);
 
    }else{
 
      fprintf(stderr,"%s: Error: unknown option: %s\n", Argv0, z);
 
      fprintf(stderr,"Use -help for a list of options.\n");
 
      return 1;
 
    }
 
  }
 

	
 
  if( zFirstCmd ){
 
    /* Run just the command that follows the database name
 
    */
 
    if( zFirstCmd[0]=='.' ){
 
      rc = do_meta_command(zFirstCmd, &data);
 
    }else{
 
      open_db(&data);
 
      rc = shell_exec(data.db, zFirstCmd, shell_callback, &data, &zErrMsg);
 
      if( zErrMsg!=0 ){
 
        fprintf(stderr,"Error: %s\n", zErrMsg);
 
        return rc!=0 ? rc : 1;
 
      }else if( rc!=0 ){
 
        fprintf(stderr,"Error: unable to process SQL \"%s\"\n", zFirstCmd);
 
        return rc;
 
      }
 
    }
 
  }else{
 
    /* Run commands received from standard input
 
    */
 
    if( stdin_is_interactive ){
 
      char *zHome;
 
      char *zHistory = 0;
 
      int nHistory;
 
      printf(
 
        "SQLite version %s %.19s\n" /*extra-version-info*/
 
        "Enter \".help\" for instructions\n"
 
        "Enter SQL statements terminated with a \";\"\n",
 
        sqlite3_libversion(), sqlite3_sourceid()
 
      );
 
      zHome = find_home_dir();
 
      if( zHome ){
 
        nHistory = strlen30(zHome) + 20;
 
        if( (zHistory = malloc(nHistory))!=0 ){
 
          sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome);
 
        }
 
      }
 
#if defined(HAVE_READLINE) && HAVE_READLINE==1
 
      if( zHistory ) read_history(zHistory);
 
#endif
 
      rc = process_input(&data, 0);
 
      if( zHistory ){
 
        stifle_history(100);
 
        write_history(zHistory);
 
        free(zHistory);
 
      }
 
      free(zHome);
 
    }else{
 
      rc = process_input(&data, stdin);
 
    }
 
  }
 
  set_table_name(&data, 0);
 
  if( data.db ){
 
    sqlite3_close(data.db);
 
  }
 
  return rc;
 
}

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)