pax_global_header00006660000000000000000000000064137714004770014524gustar00rootroot0000000000000052 comment=2fa542db43631bfef8638d686b3361539ee818e2 carbons-0.2.3/000077500000000000000000000000001377140047700131555ustar00rootroot00000000000000carbons-0.2.3/.appveyor.yml000066400000000000000000000020661377140047700156270ustar00rootroot00000000000000version: 0.2.3-dev-{build} image: Ubuntu1804 install: - sh: sudo apt-get update - sh: sudo apt-get install -y libpurple-dev libglib2.0-dev libxml2-dev libcmocka-dev mingw-w64 unzip --no-install-recommends build_script: - sh: make - sh: make win test_script: - sh: CMOCKA_MESSAGE_OUTPUT=XML CMOCKA_XML_FILE=build/cmocka_results.xml make test after_test: - sh: curl -v -F "file=@$APPVEYOR_BUILD_FOLDER/build/cmocka_results.xml" "https://ci.appveyor.com/api/testresults/junit/$APPVEYOR_JOB_ID" - sh: bash <(curl -s https://codecov.io/bash) -g test/ -B $APPVEYOR_REPO_BRANCH -b $APPVEYOR_BUILD_VERSION cache: - win32_dev artifacts: - path: build/carbons.so name: carbons-$APPVEYOR_BUILD_VERSION-$APPVEYOR_REPO_COMMIT.so - path: build/carbons.dll name: carbons-$APPVEYOR_BUILD_VERSION-$APPVEYOR_REPO_COMMIT.dll deploy: description: 'Release description' provider: GitHub auth_token: secure: cdAyB4V+IR862PUMggKUTfrWBlZa3VUg5tolJzARYajRxWLiYGzw2VQcAPpmHZsL artifact: build/carbons.so,build/carbons.dll draft: true on: APPVEYOR_REPO_TAG: true carbons-0.2.3/.gitignore000066400000000000000000000000331377140047700151410ustar00rootroot00000000000000build/ .vscode/ win32_dev/ carbons-0.2.3/CHANGELOG.md000066400000000000000000000023721377140047700147720ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.2.3] - 2020-12-25 ### Added - This file. - LICENSE file to make GitHub happy ([#39](https://github.com/gkdr/carbons/issues/39)). - The implemented XEP version to the README ([#41](https://github.com/gkdr/carbons/issues/41)). - A `carbons_internal.h` file declaring internal functions ([#33](https://github.com/gkdr/carbons/pull/33)) (needed and added by [@shtrom](https://github.com/shtrom) :) ) ### Fixed - AppVeyor will now only push tagged builds to GitHub releases. - Set `rpath` for regular build instead of just for tests ([#38](https://github.com/gkdr/carbons/pull/38)) (thanks, [@wladmis](https://github.com/wladmis)!). - Stop leaking the retrieved message body ([#42](https://github.com/gkdr/carbons/pull/42)) (thanks, [@henry-nicolas](https://github.com/henry-nicolas)!). - Preserve `CPPFLAGS` and `LDFLAGS` from env ([#43](https://github.com/gkdr/carbons/pull/43)) (thanks, [@henry-nicolas](https://github.com/henry-nicolas)!). ## [0.2.2] and below Lost to git commit logs and the GitHub releases page. carbons-0.2.3/LICENSE000066400000000000000000000432541377140047700141720ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. carbons-0.2.3/Makefile000066400000000000000000000111631377140047700146170ustar00rootroot00000000000000CC ?= gcc PKG_CONFIG ?= pkg-config LDIR=./lib BDIR=./build SDIR=./src HDIR=./headers TDIR=./test PURPLE_DIR=$(shell $(PKG_CONFIG) --variable=plugindir purple) GLIB_CFLAGS ?= $(shell $(PKG_CONFIG) --cflags glib-2.0) GLIB_LDFLAGS ?= $(shell $(PKG_CONFIG) --libs glib-2.0) LIBPURPLE_CFLAGS ?= $(shell $(PKG_CONFIG) --cflags purple) LIBPURPLE_LDFLAGS ?= $(shell $(PKG_CONFIG) --cflags purple) -L$(PURPLE_DIR) PURPLE_PLUGIN_DIR ?= $(shell $(PKG_CONFIG) --variable=plugindir purple) PURPLE_HOME_PLUGIN_DIR=$(HOME)/.purple/plugins XML2_CONFIG ?= xml2-config XML2_CFLAGS ?= $(shell $(XML2_CONFIG) --cflags) XML2_LDFLAGS ?= $(shell $(XML2_CONFIG) --libs) HEADERS=-I$(HDIR)/jabber PKGCFG_C=$(GLIB_CFLAGS) \ $(LIBPURPLE_CFLAGS) \ $(XML2_CFLAGS) PKGCFG_L=$(GLIB_LDFLAGS) \ $(LIBPURPLE_LDFLAGS) \ $(XML2_LDFLAGS) FLAGS+=-std=c11 -Wall -g -Wstrict-overflow -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_DEFAULT_SOURCE $(CPPFLAGS) CFLAGS+= $(FLAGS) $(PKGCFG_C) $(HEADERS) CFLAGS_C= $(CFLAGS) -fPIC -shared CFLAGS_T= $(CFLAGS) -O0 PLUGIN_CPPFLAGS=-DPURPLE_PLUGINS ifneq ("$(wildcard /etc/redhat-release)","") LJABBER?=-lxmpp else LJABBER?=-ljabber endif LFLAGS= $(LDFLAGS) -ldl -lm $(PKGCFG_L) $(LJABBER) -Wl,-rpath,$(PURPLE_DIR) LFLAGS_T= $(LFLAGS) -lpurple -lcmocka \ -Wl,--wrap=purple_account_is_connected \ -Wl,--wrap=purple_account_get_connection \ -Wl,--wrap=purple_account_get_protocol_id \ -Wl,--wrap=purple_account_get_username \ -Wl,--wrap=purple_accounts_get_handle \ -Wl,--wrap=purple_accounts_get_all_active \ -Wl,--wrap=purple_debug_error \ -Wl,--wrap=purple_debug_warning \ -Wl,--wrap=purple_connection_get_account \ -Wl,--wrap=purple_connection_get_protocol_data \ -Wl,--wrap=purple_find_conversation_with_account \ -Wl,--wrap=purple_conversation_new \ -Wl,--wrap=purple_conversation_write \ -Wl,--wrap=purple_plugins_find_with_id \ -Wl,--wrap=purple_signal_connect \ -Wl,--wrap=purple_signal_connect_priority \ -Wl,--wrap=jabber_add_feature \ -Wl,--wrap=jabber_iq_send all: $(BDIR)/carbons.so $(BDIR): mkdir -p build $(BDIR)/%.o: $(SDIR)/%.c $(BDIR) $(CC) $(CFLAGS_C) $(PLUGIN_CPPFLAGS) -c $(SDIR)/$*.c -o $@ $(BDIR)/carbons.so: $(BDIR)/carbons.o $(CC) $(CFLAGS_C) $(PLUGIN_CPPFLAGS) $(BDIR)/carbons.o -o $@ $(LFLAGS) $(BDIR)/carbons.a: $(BDIR)/carbons.o $(AR) rcs $@ $^ $(BDIR)/carbons.dll: $(BDIR)/carbons.o $(CC) $(CFLAGS_C) $(PLUGIN_CPPFLAGS) $(BDIR)/carbons.o -o $@ $(LFLAGS) WIN_CC ?= i686-w64-mingw32-gcc-win32 WIN32_DEV_DIR ?= win32_dev GLIB_DIR ?= glib-2.28.8 GLIB_PATH = ./$(WIN32_DEV_DIR)/$(GLIB_DIR) WIN_PIDGIN_PATH = ./$(WIN32_DEV_DIR)/pidgin-2.13.0-win32bin LIBXML2_DIR ?= libxml2-2.9.2_daa1 LIBXML2_PATH = ./$(WIN32_DEV_DIR)/$(LIBXML2_DIR) WIN_HEADERS ?= -I$(GLIB_PATH)/include/glib-2.0 \ -I$(GLIB_PATH)/lib/glib-2.0/include \ -I/usr/include/libpurple \ -I./headers/jabber \ -I$(LIBXML2_PATH)/include/libxml2 WIN_CFLAGS += $(FLAGS) $(WIN_HEADERS) $(PLUGIN_CPPFLAGS) -fPIC -shared WIN_LFLAGS = -L$(GLIB_PATH)/lib -lglib-2.0 -L$(WIN_PIDGIN_PATH) -lpurple -ljabber -L$(LIBXML2_PATH)/lib -lxml2 -static-libgcc windeps: mkdir -p $(WIN32_DEV_DIR) wget -nc -P $(WIN32_DEV_DIR) https://ftp.gnome.org/mirror/gnome.org/binaries/win32/glib/2.28/glib-dev_2.28.8-1_win32.zip unzip -n $(WIN32_DEV_DIR)/glib-dev_2.28.8-1_win32.zip -d $(GLIB_PATH) -wget -nc -O $(WIN32_DEV_DIR)/pidgin-2.13.0-win32-bin.zip https://sourceforge.net/projects/pidgin/files/Pidgin/2.13.0/pidgin-2.13.0-win32-bin.zip/download unzip -n $(WIN32_DEV_DIR)/pidgin-2.13.0-win32-bin.zip -d $(WIN32_DEV_DIR) wget -nc -P $(WIN32_DEV_DIR) https://developer.pidgin.im/static/win32/libxml2-2.9.2_daa1.tar.gz -tar xvzkf $(WIN32_DEV_DIR)/libxml2-2.9.2_daa1.tar.gz --directory $(WIN32_DEV_DIR) win: $(SDIR)/carbons.c $(BDIR) windeps $(WIN_CC) $(WIN_CFLAGS) -c ./src/carbons.c -o $(BDIR)/carbons_win.o $(WIN_CC) $(WIN_CFLAGS) $(BDIR)/carbons_win.o -o $(BDIR)/carbons.dll $(WIN_LFLAGS) install: $(BDIR)/carbons.so install -Dm0644 $(BDIR)/carbons.so $(DESTDIR)$(PURPLE_PLUGIN_DIR)/carbons.so install-home: $(BDIR)/carbons.so install -Dm0644 $(BDIR)/carbons.so $(PURPLE_HOME_PLUGIN_DIR)/carbons.so .PHONY: test test: $(TDIR)/test_carbons.c $(BDIR) $(CC) $(CFLAGS_T) -c $< -o $(BDIR)/$@.o $(CC) $(CFLAGS_T) --coverage -c $(SDIR)/carbons.c -o $(BDIR)/carbons_coverage.o $(CC) $(CFLAGS_T) --coverage $(PURPLE_DIR)/libjabber.so.0 $(BDIR)/$@.o $(BDIR)/carbons_coverage.o -o $(BDIR)/$@ $(LFLAGS_T) -$(BDIR)/$@ 2>&1 | grep -Ev ".*CRITICAL.*" | tr -s '\n' # filter annoying and irrelevant glib output .PHONY: coverage coverage: test gcovr -r . --html --html-details -o build/coverage.html gcovr -r . -s .PHONY: clean clean: rm -rf $(BDIR) .PHONY: clean-all clean-all: clean rm -rf $(WIN32_DEV_DIR) carbons-0.2.3/Makefile.mingw000066400000000000000000000023741377140047700157430ustar00rootroot00000000000000PURPLE_PLUGIN_DIR = c:/Program\ Files\ \(x86\)/Pidgin/plugins PIDGIN_DIR ?= ../pidgin-2.11.0 LIBPURPLE_DIR ?= $(PIDGIN_DIR)/libpurple WIN32_DEV_TOP ?= $(PIDGIN_DIR)/../win32-dev LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.9.0 CC := $(WIN32_DEV_TOP)/mingw-4.7.2/bin/gcc LDIR = ./lib BDIR = ./build SDIR = ./src HDIR = ./headers HEADERS = -I$(HDIR)/jabber PKGCFG_C = -I$(WIN32_DEV_TOP)/glib-2.28.8/include -I$(WIN32_DEV_TOP)/glib-2.28.8/include/glib-2.0 -I$(WIN32_DEV_TOP)/glib-2.28.8/lib/glib-2.0/include -I$(LIBPURPLE_DIR) -I$(LIBPURPLE_DIR)/protocols/jabber -I$(LIBXML2_TOP)/include/libxml2 PKGCFG_L = -L$(WIN32_DEV_TOP)/glib-2.28.8/lib -lglib-2.0 -L$(LIBPURPLE_DIR) -lpurple -L$(LIBPURPLE_DIR)/protocols/jabber -L$(LIBXML2_TOP)/lib -lxml2 CFLAGS = -std=c11 -Wall -g -Wstrict-overflow -D_XOPEN_SOURCE=700 -D_BSD_SOURCE $(PKGCFG_C) $(HEADERS) LFLAGS = $(PKGCFG_L) -ljabber -static-libgcc all: $(BDIR)/carbons.dll $(BDIR): mkdir -p build $(BDIR)/carbons.dll: $(SDIR)/carbons.c $(BDIR) $(CC) $(CFLAGS) -c $(SDIR)/carbons.c -o $(BDIR)/carbons.o $(CC) -shared $(CFLAGS) $(BDIR)/carbons.o -o $@ $(LFLAGS) install: $(BDIR)/carbons.dll mkdir -p $(PURPLE_PLUGIN_DIR) install -p $(BDIR)/carbons.dll $(PURPLE_PLUGIN_DIR)/carbons.dll .PHONY: clean clean: rm -rf $(BDIR) carbons-0.2.3/README.md000066400000000000000000000047461377140047700144470ustar00rootroot00000000000000# carbons 0.2.3 [![Build status](https://ci.appveyor.com/api/projects/status/0t32ouomatf2teld/branch/dev?svg=true)](https://ci.appveyor.com/project/gkdr/carbons/branch/dev) [![codecov](https://codecov.io/gh/gkdr/carbons/branch/dev/graph/badge.svg)](https://codecov.io/gh/gkdr/carbons) [![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/gkdr/carbons.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/gkdr/carbons/context:cpp) Experimental [XEP-0280: Message Carbons](https://xmpp.org/extensions/xep-0280.html) (v0.13.2) plugin for libpurple (Pidgin, Finch, etc.). It enables you to have a consistent view of both sent and received messages between all devices which are online at the same time. ## Installation You can find compiled versions of this plugin for both Linux and Windows on [the GitHub releases page](https://github.com/gkdr/carbons/releases). To get the latest build for both operating systems you can head over to [the artifacts page of this project's current build on AppVeyor](https://ci.appveyor.com/project/gkdr/carbons/build/artifacts). ## Usage On startup, it sends a feature discovery request to the server and automatically enables message carbons if the server lists it among its supported features. If something is not working right, consult the debug window. ## Building it yourself ### Linux 1. Install the dependencies (`libpurple-dev`, `libglib2.0-dev`, `libxml2-dev`) 2. `git clone https://github.com/gkdr/carbons.git` 3. `cd carbons` 4. `make` 5. A final `make install` should copy the plugin into your libpurple plugin dir, or `make install-home` to copy it into `~/.purple/plugins`. ### MacOS Install dependencies using Homebrew. ``` brew install glib libxml2 ``` Get a copy of the libpurple soure (from Pidgin), and prepare it so we can use it during the build. ``` hg clone https://bitbucket.org/pidgin/main pidgin cd pidgin hg checkout v2.10.12 ./configure $(./configure --help | grep -i -- --disable | awk '{ print $1 }') ``` ``` make LIBPURPLE_CFLAGS=-I${PWD}/pidgin/libpurple LIBPURPLE_LDFLAGS=/Applications/Adium.app/Contents/Frameworks/libpurple.framework/libpurple LJABBER= ``` ### Windows You can make use of the `Makefile.mingw` by EionRobb. For this, you have to set up a build environment as described in https://developer.pidgin.im/wiki/BuildingWinPidgin. ## Caveats Note that this only synchronizes messages of devices that are online at the same time - for history synchronization, MAM is needed. There is currently no libpurple plugin for this. carbons-0.2.3/headers/000077500000000000000000000000001377140047700145705ustar00rootroot00000000000000carbons-0.2.3/headers/jabber/000077500000000000000000000000001377140047700160155ustar00rootroot00000000000000carbons-0.2.3/headers/jabber/adhoccommands.h000077500000000000000000000032241377140047700207720ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_ADHOCCOMMANDS_H_ #define PURPLE_JABBER_ADHOCCOMMANDS_H_ #include "jabber.h" /* Implementation of XEP-0050 */ void jabber_adhoc_disco_result_cb(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *packet, gpointer data); void jabber_adhoc_execute(JabberStream *js, JabberAdHocCommands *cmd); void jabber_adhoc_execute_action(PurpleBlistNode *node, gpointer data); void jabber_adhoc_got_list(JabberStream *js, const char *from, xmlnode *query); void jabber_adhoc_server_get_list(JabberStream *js); void jabber_adhoc_init_server_commands(JabberStream *js, GList **m); #endif /* PURPLE_JABBER_ADHOCCOMMANDS_H_ */ carbons-0.2.3/headers/jabber/auth.h000077500000000000000000000050631377140047700171360ustar00rootroot00000000000000/** * @file auth.h Authentication routines * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_AUTH_H_ #define PURPLE_JABBER_AUTH_H_ typedef struct _JabberSaslMech JabberSaslMech; #include "jabber.h" #include "xmlnode.h" typedef enum { JABBER_SASL_STATE_FAIL = -1, /* Abort, Retry, Fail? */ JABBER_SASL_STATE_OK = 0, /* Hooray! */ JABBER_SASL_STATE_CONTINUE = 1 /* More authentication required */ } JabberSaslState; struct _JabberSaslMech { gint8 priority; /* Higher priority will be tried before lower priority */ const gchar *name; JabberSaslState (*start)(JabberStream *js, xmlnode *mechanisms, xmlnode **reply, char **msg); JabberSaslState (*handle_challenge)(JabberStream *js, xmlnode *packet, xmlnode **reply, char **msg); JabberSaslState (*handle_success)(JabberStream *js, xmlnode *packet, char **msg); JabberSaslState (*handle_failure)(JabberStream *js, xmlnode *packet, xmlnode **reply, char **msg); void (*dispose)(JabberStream *js); }; void jabber_auth_start(JabberStream *js, xmlnode *packet); void jabber_auth_start_old(JabberStream *js); void jabber_auth_handle_challenge(JabberStream *js, xmlnode *packet); void jabber_auth_handle_success(JabberStream *js, xmlnode *packet); void jabber_auth_handle_failure(JabberStream *js, xmlnode *packet); JabberSaslMech *jabber_auth_get_plain_mech(void); JabberSaslMech *jabber_auth_get_digest_md5_mech(void); JabberSaslMech **jabber_auth_get_scram_mechs(gint *count); #ifdef HAVE_CYRUS_SASL JabberSaslMech *jabber_auth_get_cyrus_mech(void); #endif void jabber_auth_add_mech(JabberSaslMech *); void jabber_auth_remove_mech(JabberSaslMech *); void jabber_auth_init(void); void jabber_auth_uninit(void); #endif /* PURPLE_JABBER_AUTH_H_ */ carbons-0.2.3/headers/jabber/auth_digest_md5.h000077500000000000000000000025631377140047700212440ustar00rootroot00000000000000/** * @file auth_digest_md5.h Implementation of SASL DIGEST-MD5 authentication * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_AUTH_DIGEST_MD5_H_ #define PURPLE_JABBER_AUTH_DIGEST_MD5_H_ #include "internal.h" /* * Every function in this file is ONLY exposed for tests. * DO NOT USE ANYTHING HERE OR YOU WILL BE SENT TO THE PIT OF DESPAIR. */ /* * Parse a DIGEST-MD5 challenge. */ GHashTable *jabber_auth_digest_md5_parse(const char *challenge); #endif /* PURPLE_JABBER_AUTH_DIGEST_MD5_H_ */ carbons-0.2.3/headers/jabber/auth_scram.h000077500000000000000000000061001377140047700203140ustar00rootroot00000000000000/** * @file auth_scram.h Implementation of SASL-SCRAM authentication * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_AUTH_SCRAM_H_ #define PURPLE_JABBER_AUTH_SCRAM_H_ /* * Every function in this file is ONLY exposed for tests. * DO NOT USE ANYTHING HERE OR YOU WILL BE SENT TO THE PIT OF DESPAIR. */ /* Per-connection state stored between messages. * This is stored in js->auth_data_mech. */ typedef struct { const char *mech_substr; const char *name; guint size; } JabberScramHash; typedef struct { const JabberScramHash *hash; char *cnonce; GString *auth_message; GString *client_proof; GString *server_signature; gchar *password; gboolean channel_binding; int step; } JabberScramData; #include "auth.h" /** * Implements the Hi() function as described in the SASL-SCRAM I-D. * * @param hash The struct corresponding to the hash function to be used. * @param str The string to perform the PBKDF2 operation on. * @param salt The salt. * @param iterations The number of iterations to perform. * * @returns A newly allocated string containing the result. The string is * NOT null-terminated and its length is the length of the binary * output of the hash function in-use. */ guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str, GString *salt, guint iterations); /** * Calculates the proofs as described in Section 3 of the SASL-SCRAM I-D. * * @param data A JabberScramData structure. hash and auth_message must be * set. client_proof and server_signature will be set as a result * of this function. * @param salt The salt (as specified by the server) * @param iterations The number of iterations to perform. * * @returns TRUE if the proofs were successfully calculated. FALSE otherwise. */ gboolean jabber_scram_calc_proofs(JabberScramData *data, GString *salt, guint iterations); /** * Feed the algorithm with the data from the server. */ gboolean jabber_scram_feed_parser(JabberScramData *data, gchar *in, gchar **out); /** * Clean up and destroy the data struct */ void jabber_scram_data_destroy(JabberScramData *data); #endif /* PURPLE_JABBER_AUTH_SCRAM_H_ */ carbons-0.2.3/headers/jabber/bosh.h000077500000000000000000000033361377140047700171310ustar00rootroot00000000000000/** * @file bosh.h Bidirectional-streams over Synchronous HTTP (BOSH) (XEP-0124 and XEP-0206) * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_BOSH_H_ #define PURPLE_JABBER_BOSH_H_ typedef struct _PurpleBOSHConnection PurpleBOSHConnection; #include "jabber.h" void jabber_bosh_init(void); void jabber_bosh_uninit(void); PurpleBOSHConnection* jabber_bosh_connection_init(JabberStream *js, const char *url); void jabber_bosh_connection_destroy(PurpleBOSHConnection *conn); gboolean jabber_bosh_connection_is_ssl(PurpleBOSHConnection *conn); void jabber_bosh_connection_send_keepalive(PurpleBOSHConnection *conn); void jabber_bosh_connection_connect(PurpleBOSHConnection *conn); void jabber_bosh_connection_close(PurpleBOSHConnection *conn); void jabber_bosh_connection_send_raw(PurpleBOSHConnection *conn, const char *data); #endif /* PURPLE_JABBER_BOSH_H_ */ carbons-0.2.3/headers/jabber/buddy.h000077500000000000000000000075271377140047700173130ustar00rootroot00000000000000/** * @file buddy.h Buddy handlers * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_BUDDY_H_ #define PURPLE_JABBER_BUDDY_H_ typedef struct _JabberBuddy JabberBuddy; #include "jabber.h" #include "caps.h" #include "jutil.h" struct _JabberBuddy { /** * A sorted list of resources in priority descending order. * This means that the first resource in the list is the * "most available" (see resource_compare_cb in buddy.c for * details). Don't play with this yourself, let * jabber_buddy_track_resource and jabber_buddy_remove_resource do it. */ GList *resources; char *error_msg; enum { JABBER_INVISIBLE_NONE = 0, JABBER_INVISIBLE_SERVER = 1 << 1, JABBER_INVIS_BUDDY = 1 << 2 } invisible; enum { JABBER_SUB_NONE = 0, JABBER_SUB_PENDING = 1 << 1, JABBER_SUB_TO = 1 << 2, JABBER_SUB_FROM = 1 << 3, JABBER_SUB_BOTH = (JABBER_SUB_TO | JABBER_SUB_FROM), JABBER_SUB_REMOVE = 1 << 4 } subscription; }; typedef struct _JabberAdHocCommands { char *jid; char *node; char *name; } JabberAdHocCommands; typedef struct _JabberBuddyResource { JabberBuddy *jb; char *name; int priority; JabberBuddyState state; char *status; time_t idle; JabberCapabilities capabilities; char *thread_id; enum { JABBER_CHAT_STATES_UNKNOWN, JABBER_CHAT_STATES_UNSUPPORTED, JABBER_CHAT_STATES_SUPPORTED } chat_states; struct { char *version; char *name; char *os; } client; /* tz_off == PURPLE_NO_TZ_OFF when unset */ long tz_off; struct { JabberCapsClientInfo *info; GList *exts; } caps; GList *commands; gboolean commands_fetched; } JabberBuddyResource; void jabber_buddy_free(JabberBuddy *jb); JabberBuddy *jabber_buddy_find(JabberStream *js, const char *name, gboolean create); JabberBuddyResource *jabber_buddy_find_resource(JabberBuddy *jb, const char *resource); JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource, int priority, JabberBuddyState state, const char *status); void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource); void jabber_buddy_get_info(PurpleConnection *gc, const char *who); GList *jabber_blist_node_menu(PurpleBlistNode *node); void jabber_set_info(PurpleConnection *gc, const char *info); void jabber_setup_set_info(PurplePluginAction *action); void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); void jabber_user_search(JabberStream *js, const char *directory); void jabber_user_search_begin(PurplePluginAction *); void jabber_buddy_remove_all_pending_buddy_info_requests(JabberStream *js); void jabber_vcard_fetch_mine(JabberStream *js); gboolean jabber_resource_know_capabilities(const JabberBuddyResource *jbr); gboolean jabber_resource_has_capability(const JabberBuddyResource *jbr, const gchar *cap); gboolean jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap); const gchar * jabber_resource_get_identity_category_type(const JabberBuddyResource *jbr, const gchar *category); #endif /* PURPLE_JABBER_BUDDY_H_ */ carbons-0.2.3/headers/jabber/caps.h000077500000000000000000000102561377140047700171230ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_CAPS_H_ #define PURPLE_JABBER_CAPS_H_ typedef struct _JabberCapsClientInfo JabberCapsClientInfo; #include "jabber.h" /* Implementation of XEP-0115 - Entity Capabilities */ typedef struct _JabberCapsNodeExts JabberCapsNodeExts; typedef struct _JabberCapsTuple { const char *node; const char *ver; const char *hash; } JabberCapsTuple; struct _JabberCapsClientInfo { GList *identities; /* JabberIdentity */ GList *features; /* char * */ GList *forms; /* xmlnode * */ JabberCapsNodeExts *exts; const JabberCapsTuple tuple; }; /* * This stores a set of exts "known" for a specific node (which indicates * a specific client -- for reference, Pidgin, Finch, Meebo, et al share one * node.) In XEP-0115 v1.3, exts are used for features that may or may not be * present at a given time (PEP things, buzz might be disabled, etc). * * This structure is shared among all JabberCapsClientInfo instances matching * a specific node (if the capstable key->hash == NULL, which indicates that * the ClientInfo is using v1.3 caps as opposed to v1.5 caps). * * It's only exposed so that jabber_resource_has_capability can use it. * Everyone else, STAY AWAY! */ struct _JabberCapsNodeExts { guint ref; GHashTable *exts; /* char *ext_name -> GList *features */ }; typedef void (*jabber_caps_get_info_cb)(JabberCapsClientInfo *info, GList *exts, gpointer user_data); void jabber_caps_init(void); void jabber_caps_uninit(void); /** * Check whether all of the exts in a char* array are known to the given info. */ gboolean jabber_caps_exts_known(const JabberCapsClientInfo *info, char **exts); /** * Main entity capabilites function to get the capabilities of a contact. * * The callback will be called synchronously if we already have the * capabilities for the specified (node,ver,hash) (and, if exts are specified, * if we know what each means) * * @param exts A g_strsplit'd (NULL-terminated) array of strings. This * function is responsible for freeing it. */ void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, const char *ver, const char *hash, char **exts, jabber_caps_get_info_cb cb, gpointer user_data); /** * Takes a JabberCapsClientInfo pointer and returns the caps hash according to * XEP-0115 Version 1.5. * * @param info A JabberCapsClientInfo pointer. * @param hash Hash cipher to be used. Either sha-1 or md5. * @return The base64 encoded SHA-1 hash; must be freed by caller */ gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info, const char *hash); /** * Calculate SHA1 hash for own featureset. */ void jabber_caps_calculate_own_hash(JabberStream *js); /** Get the current caps hash. * @ret hash **/ const gchar* jabber_caps_get_own_hash(JabberStream *js); /** * Broadcast a new calculated hash using a stanza. */ void jabber_caps_broadcast_change(void); /** * Parse the element from an IQ stanza into a JabberCapsClientInfo * struct. * * Exposed for tests * * @param query The 'query' element from an IQ reply stanza. * @returns A JabberCapsClientInfo struct, or NULL on error */ JabberCapsClientInfo *jabber_caps_parse_client_info(xmlnode *query); #endif /* PURPLE_JABBER_CAPS_H_ */ carbons-0.2.3/headers/jabber/chat.h000077500000000000000000000107421377140047700171140ustar00rootroot00000000000000/** * @file chat.h Chat stuff * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_CHAT_H_ #define PURPLE_JABBER_CHAT_H_ #include "internal.h" #include "connection.h" #include "conversation.h" #include "request.h" #include "roomlist.h" #include "jabber.h" typedef struct _JabberChatMember { char *handle; char *jid; } JabberChatMember; typedef struct _JabberChat { JabberStream *js; char *room; char *server; char *handle; GHashTable *components; int id; PurpleConversation *conv; gboolean muc; gboolean xhtml; PurpleRequestType config_dialog_type; void *config_dialog_handle; GHashTable *members; gboolean left; time_t joined; } JabberChat; GList *jabber_chat_info(PurpleConnection *gc); GHashTable *jabber_chat_info_defaults(PurpleConnection *gc, const char *chat_name); char *jabber_get_chat_name(GHashTable *data); /** * in-prpl function for joining a chat room. Doesn't require sticking goop * into a hash table. * * @param room The room to join. This MUST be normalized already. * @param server The server the room is on. This MUST be normalized already. * @param password The password (if required) to join the room. May be NULL. * @param data The chat hash table. May be NULL (it will be generated * for current core<>prpl API interface.) */ JabberChat *jabber_join_chat(JabberStream *js, const char *room, const char *server, const char *handle, const char *password, GHashTable *data); void jabber_chat_join(PurpleConnection *gc, GHashTable *data); JabberChat *jabber_chat_find(JabberStream *js, const char *room, const char *server); JabberChat *jabber_chat_find_by_id(JabberStream *js, int id); JabberChat *jabber_chat_find_by_conv(PurpleConversation *conv); void jabber_chat_destroy(JabberChat *chat); void jabber_chat_free(JabberChat *chat); gboolean jabber_chat_find_buddy(PurpleConversation *conv, const char *name); void jabber_chat_invite(PurpleConnection *gc, int id, const char *message, const char *name); void jabber_chat_leave(PurpleConnection *gc, int id); char *jabber_chat_buddy_real_name(PurpleConnection *gc, int id, const char *who); void jabber_chat_request_room_configure(JabberChat *chat); void jabber_chat_create_instant_room(JabberChat *chat); void jabber_chat_register(JabberChat *chat); void jabber_chat_change_topic(JabberChat *chat, const char *topic); void jabber_chat_set_topic(PurpleConnection *gc, int id, const char *topic); gboolean jabber_chat_change_nick(JabberChat *chat, const char *nick); void jabber_chat_part(JabberChat *chat, const char *msg); void jabber_chat_track_handle(JabberChat *chat, const char *handle, const char *jid, const char *affiliation, const char *role); void jabber_chat_remove_handle(JabberChat *chat, const char *handle); gboolean jabber_chat_ban_user(JabberChat *chat, const char *who, const char *why); gboolean jabber_chat_affiliate_user(JabberChat *chat, const char *who, const char *affiliation); gboolean jabber_chat_affiliation_list(JabberChat *chat, const char *affiliation); gboolean jabber_chat_role_user(JabberChat *chat, const char *who, const char *role, const char *why); gboolean jabber_chat_role_list(JabberChat *chat, const char *role); PurpleRoomlist *jabber_roomlist_get_list(PurpleConnection *gc); void jabber_roomlist_cancel(PurpleRoomlist *list); void jabber_chat_disco_traffic(JabberChat *chat); char *jabber_roomlist_room_serialize(PurpleRoomlistRoom *room); gboolean jabber_chat_all_participants_have_capability(const JabberChat *chat, const gchar *cap); guint jabber_chat_get_num_participants(const JabberChat *chat); #endif /* PURPLE_JABBER_CHAT_H_ */ carbons-0.2.3/headers/jabber/data.h000077500000000000000000000061241377140047700171050ustar00rootroot00000000000000/* * purple - Jabber Service Discovery * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_DATA_H #define PURPLE_JABBER_DATA_H #include "xmlnode.h" #include "jabber.h" #include #define JABBER_DATA_MAX_SIZE 8192 typedef struct { char *cid; char *type; gsize size; gpointer data; gboolean ephemeral; } JabberData; typedef void (JabberDataRequestCallback)(JabberData *data, gchar *alt, gpointer userdata); /* creates a JabberData instance from raw data */ JabberData *jabber_data_create_from_data(gconstpointer data, gsize size, const char *type, gboolean ephemeral, JabberStream *js); /* create a JabberData instance from an XML "data" element (as defined by XEP 0231 */ JabberData *jabber_data_create_from_xml(xmlnode *tag); /* destroy a JabberData instance, NOT to be used on data that has been associated, since they get "owned" */ void jabber_data_destroy(JabberData *data); const char *jabber_data_get_cid(const JabberData *data); const char *jabber_data_get_type(const JabberData *data); gsize jabber_data_get_size(const JabberData *data); gpointer jabber_data_get_data(const JabberData *data); /* returns the XML definition for the data element */ xmlnode *jabber_data_get_xml_definition(const JabberData *data); /* returns an XHTML-IM "img" tag given a data instance */ xmlnode *jabber_data_get_xhtml_im(const JabberData *data, const gchar *alt); void jabber_data_request(JabberStream *js, const gchar *cid, const gchar *who, gchar *alt, gboolean ephemeral, JabberDataRequestCallback cb, gpointer userdata); /* lookup functions */ const JabberData *jabber_data_find_local_by_alt(const gchar *alt); const JabberData *jabber_data_find_local_by_cid(const gchar *cid); const JabberData *jabber_data_find_remote_by_cid(JabberStream *js, const gchar *who, const gchar *cid); /* store data objects */ void jabber_data_associate_local(JabberData *data, const gchar *alt); void jabber_data_associate_remote(JabberStream *js, const gchar *who, JabberData *data); /* handles iq requests */ void jabber_data_parse(JabberStream *js, const char *who, JabberIqType type, const char *id, xmlnode *data_node); void jabber_data_init(void); void jabber_data_uninit(void); #endif /* PURPLE_JABBER_DATA_H */ carbons-0.2.3/headers/jabber/disco.h000077500000000000000000000036341377140047700173000ustar00rootroot00000000000000/** * @file disco.h Jabber Service Discovery * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_DISCO_H_ #define PURPLE_JABBER_DISCO_H_ #include "jabber.h" typedef struct _JabberDiscoItem { const char *jid; /* MUST */ const char *node; /* SHOULD */ const char *name; /* MAY */ } JabberDiscoItem; typedef void (JabberDiscoInfoCallback)(JabberStream *js, const char *who, JabberCapabilities capabilities, gpointer data); typedef void (JabberDiscoItemsCallback)(JabberStream *js, const char *jid, const char *node, GSList *items, gpointer data); void jabber_disco_info_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *in_query); void jabber_disco_items_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *query); void jabber_disco_items_server(JabberStream *js); void jabber_disco_info_do(JabberStream *js, const char *who, JabberDiscoInfoCallback *callback, gpointer data); #endif /* PURPLE_JABBER_DISCO_H_ */ carbons-0.2.3/headers/jabber/facebook_roster.h000077500000000000000000000024141377140047700213410ustar00rootroot00000000000000/** * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_XMPP_FACEBOOK_ROSTER_H_ #define PURPLE_XMPP_FACEBOOK_ROSTER_H_ #include "jabber.h" /* removes deleted buddies from the list */ void jabber_facebook_roster_cleanup(JabberStream *js, xmlnode *query); /* ignores facebook roster quirks */ gboolean jabber_facebook_roster_incoming(JabberStream *js, xmlnode *item); #endif /* PURPLE_XMPP_FACEBOOK_ROSTER_H_ */ carbons-0.2.3/headers/jabber/ibb.h000077500000000000000000000110411377140047700167220ustar00rootroot00000000000000/* * purple - Jabber Service Discovery * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_IBB_H_ #define PURPLE_JABBER_IBB_H_ #include "jabber.h" #include "iq.h" typedef struct _JabberIBBSession JabberIBBSession; typedef void (JabberIBBDataCallback)(JabberIBBSession *, const gpointer data, gsize size); typedef void (JabberIBBOpenedCallback)(JabberIBBSession *); typedef void (JabberIBBClosedCallback)(JabberIBBSession *); typedef void (JabberIBBErrorCallback)(JabberIBBSession *); typedef void (JabberIBBSentCallback)(JabberIBBSession *); typedef gboolean (JabberIBBOpenHandler)(JabberStream *js, const char *from, const char *id, xmlnode *open); typedef enum { JABBER_IBB_SESSION_NOT_OPENED, JABBER_IBB_SESSION_OPENED, JABBER_IBB_SESSION_CLOSED, JABBER_IBB_SESSION_ERROR } JabberIBBSessionState; struct _JabberIBBSession { JabberStream *js; gchar *who; gchar *sid; gchar *id; guint16 send_seq; guint16 recv_seq; gsize block_size; /* session state */ JabberIBBSessionState state; /* user data (f.ex. a handle to a PurpleXfer) */ gpointer user_data; /* callbacks */ JabberIBBOpenedCallback *opened_cb; JabberIBBSentCallback *data_sent_cb; JabberIBBClosedCallback *closed_cb; /* callback for receiving data */ JabberIBBDataCallback *data_received_cb; JabberIBBErrorCallback *error_cb; /* store the last sent IQ (to permit cancel of callback) */ gchar *last_iq_id; }; JabberIBBSession *jabber_ibb_session_create(JabberStream *js, const gchar *sid, const gchar *who, gpointer user_data); JabberIBBSession *jabber_ibb_session_create_from_xmlnode(JabberStream *js, const gchar *from, const gchar *id, xmlnode *open, gpointer user_data); void jabber_ibb_session_destroy(JabberIBBSession *sess); void jabber_ibb_session_set_opened_callback(JabberIBBSession *sess, JabberIBBOpenedCallback *cb); void jabber_ibb_session_set_data_sent_callback(JabberIBBSession *sess, JabberIBBSentCallback *cb); void jabber_ibb_session_set_closed_callback(JabberIBBSession *sess, JabberIBBClosedCallback *cb); void jabber_ibb_session_set_data_received_callback(JabberIBBSession *sess, JabberIBBDataCallback *cb); void jabber_ibb_session_set_error_callback(JabberIBBSession *sess, JabberIBBErrorCallback *cb); void jabber_ibb_session_open(JabberIBBSession *sess); void jabber_ibb_session_close(JabberIBBSession *sess); void jabber_ibb_session_accept(JabberIBBSession *sess); void jabber_ibb_session_send_data(JabberIBBSession *sess, gconstpointer data, gsize size); const gchar *jabber_ibb_session_get_sid(const JabberIBBSession *sess); JabberStream *jabber_ibb_session_get_js(JabberIBBSession *sess); const gchar *jabber_ibb_session_get_who(const JabberIBBSession *sess); guint16 jabber_ibb_session_get_send_seq(const JabberIBBSession *sess); guint16 jabber_ibb_session_get_recv_seq(const JabberIBBSession *sess); JabberIBBSessionState jabber_ibb_session_get_state(const JabberIBBSession *sess); gsize jabber_ibb_session_get_block_size(const JabberIBBSession *sess); void jabber_ibb_session_set_block_size(JabberIBBSession *sess, gsize size); /* get maximum size data block to send (in bytes) (before encoded to BASE64) */ gsize jabber_ibb_session_get_max_data_size(const JabberIBBSession *sess); gpointer jabber_ibb_session_get_user_data(JabberIBBSession *sess); /* handle incoming packet */ void jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type, const char *id, xmlnode *child); /* add a handler for open session */ void jabber_ibb_register_open_handler(JabberIBBOpenHandler *cb); void jabber_ibb_unregister_open_handler(JabberIBBOpenHandler *cb); void jabber_ibb_init(void); void jabber_ibb_uninit(void); #endif /* PURPLE_JABBER_IBB_H_ */ carbons-0.2.3/headers/jabber/iq.h000077500000000000000000000103341377140047700166030ustar00rootroot00000000000000/** * @file iq.h JabberID handlers * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_IQ_H_ #define PURPLE_JABBER_IQ_H_ typedef enum { JABBER_IQ_SET, JABBER_IQ_GET, JABBER_IQ_RESULT, JABBER_IQ_ERROR, JABBER_IQ_NONE } JabberIqType; #include "jabber.h" #include "connection.h" typedef struct _JabberIq JabberIq; typedef struct _JabberIqCallbackData JabberIqCallbackData; /** * A JabberIqHandler is called to process an incoming IQ stanza. * Handlers typically process unsolicited incoming GETs or SETs for their * registered namespace, but may be called to handle the results of a * GET or SET that we generated if no JabberIqCallback was generated * The handler may be called for the results of a GET or SET (RESULT or ERROR) * that we generated * if the generating function did not register a JabberIqCallback. * * @param js The JabberStream object. * @param from The remote entity (the from attribute on the stanza) * @param type The IQ type. * @param id The IQ id (the id attribute on the stanza) * @param child The child element of the stanza that matches the name * and namespace registered with jabber_iq_register_handler. * * @see jabber_iq_register_handler() * @see JabberIqCallback */ typedef void (JabberIqHandler)(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *child); /** * A JabberIqCallback is called to process the results of a GET or SET that * we send to a remote entity. The callback is matched based on the id * of the incoming stanza (which matches the one on the initial stanza). * * @param js The JabberStream object. * @param from The remote entity (the from attribute on the stanza) * @param type The IQ type. The only possible values are JABBER_IQ_RESULT * and JABBER_IQ_ERROR. * @param id The IQ id (the id attribute on the stanza) * @param packet The stanza * @param data The callback data passed to jabber_iq_set_callback() * * @see jabber_iq_set_callback() */ typedef void (JabberIqCallback)(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *packet, gpointer data); struct _JabberIq { JabberIqType type; char *id; xmlnode *node; JabberIqCallback *callback; gpointer callback_data; JabberStream *js; }; JabberIq *jabber_iq_new(JabberStream *js, JabberIqType type); JabberIq *jabber_iq_new_query(JabberStream *js, JabberIqType type, const char *xmlns); void jabber_iq_parse(JabberStream *js, xmlnode *packet); void jabber_iq_callbackdata_free(JabberIqCallbackData *jcd); void jabber_iq_remove_callback_by_id(JabberStream *js, const char *id); void jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *cb, gpointer data); void jabber_iq_set_id(JabberIq *iq, const char *id); void jabber_iq_send(JabberIq *iq); void jabber_iq_free(JabberIq *iq); void jabber_iq_init(void); void jabber_iq_uninit(void); void jabber_iq_register_handler(const char *node, const char *xmlns, JabberIqHandler *func); /* Connected to namespace-handler registration signals */ void jabber_iq_signal_register(const gchar *node, const gchar *xmlns); void jabber_iq_signal_unregister(const gchar *node, const gchar *xmlns); #endif /* PURPLE_JABBER_IQ_H_ */ carbons-0.2.3/headers/jabber/jabber.h000077500000000000000000000311301377140047700174140ustar00rootroot00000000000000/** * @file jabber.h * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_H_ #define PURPLE_JABBER_H_ typedef enum { JABBER_CAP_NONE = 0, /* JABBER_CAP_XHTML = 1 << 0, */ /* JABBER_CAP_COMPOSING = 1 << 1, */ JABBER_CAP_SI = 1 << 2, JABBER_CAP_SI_FILE_XFER = 1 << 3, JABBER_CAP_BYTESTREAMS = 1 << 4, JABBER_CAP_IBB = 1 << 5, JABBER_CAP_CHAT_STATES = 1 << 6, JABBER_CAP_IQ_SEARCH = 1 << 7, JABBER_CAP_IQ_REGISTER = 1 << 8, /* Google Talk extensions: * http://code.google.com/apis/talk/jep_extensions/extensions.html */ JABBER_CAP_GMAIL_NOTIFY = 1 << 9, JABBER_CAP_GOOGLE_ROSTER = 1 << 10, JABBER_CAP_PING = 1 << 11, JABBER_CAP_ADHOC = 1 << 12, JABBER_CAP_BLOCKING = 1 << 13, JABBER_CAP_ITEMS = 1 << 14, JABBER_CAP_ROSTER_VERSIONING = 1 << 15, JABBER_CAP_FACEBOOK = 1 << 16, JABBER_CAP_RETRIEVED = 1 << 31 } JabberCapabilities; typedef struct _JabberStream JabberStream; #include #include #include "circbuffer.h" #include "connection.h" #include "dnsquery.h" #include "dnssrv.h" #include "media.h" #include "mediamanager.h" #include "roomlist.h" #include "sslconn.h" #include "namespaces.h" #include "auth.h" #include "iq.h" #include "jutil.h" #include "xmlnode.h" #include "buddy.h" #include "bosh.h" #ifdef HAVE_CYRUS_SASL #include #endif #define CAPS0115_NODE "http://pidgin.im/" #define JABBER_DEFAULT_REQUIRE_TLS "require_starttls" #define JABBER_DEFAULT_FT_PROXIES "proxy.eu.jabber.org" /* Index into attention_types list */ #define JABBER_BUZZ 0 typedef enum { JABBER_STREAM_OFFLINE, JABBER_STREAM_CONNECTING, JABBER_STREAM_INITIALIZING, JABBER_STREAM_INITIALIZING_ENCRYPTION, JABBER_STREAM_AUTHENTICATING, JABBER_STREAM_POST_AUTH, JABBER_STREAM_CONNECTED } JabberStreamState; struct _JabberStream { int fd; PurpleSrvTxtQueryData *srv_query_data; xmlParserCtxt *context; xmlnode *current; struct { guint8 major; guint8 minor; } protocol_version; JabberSaslMech *auth_mech; gpointer auth_mech_data; /** * The header from the opening tag. This being NULL is treated * as a special condition in the parsing code (signifying the next * stanza started is an opening stream tag), and its being missing on * the stream header is treated as a fatal error. */ char *stream_id; JabberStreamState state; GHashTable *buddies; /* * This boolean was added to eliminate a heinous bug where we would * get into a loop with the server and move a buddy back and forth * from one group to another. * * The sequence goes something like this: * 1. Our resource and another resource both approve an authorization * request at the exact same time. We put the buddy in group A and * the other resource put the buddy in group B. * 2. The server receives the roster add for group B and sends us a * roster push. * 3. We receive this roster push and modify our local blist. This * triggers us to send a roster add for group B. * 4. The server recieves our earlier roster add for group A and sends * us a roster push. * 5. We receive this roster push and modify our local blist. This * triggers us to send a roster add for group A. * 6. The server receives our earlier roster add for group B and sends * us a roster push. * (repeat steps 3 through 6 ad infinitum) * * This boolean is used to short-circuit the sending of a roster add * when we receive a roster push. * * See these bug reports: * http://trac.adiumx.com/ticket/8834 * http://developer.pidgin.im/ticket/5484 * http://developer.pidgin.im/ticket/6188 */ gboolean currently_parsing_roster_push; GHashTable *chats; GList *chat_servers; PurpleRoomlist *roomlist; GList *user_directories; GHashTable *iq_callbacks; int next_id; GList *bs_proxies; GList *oob_file_transfers; GList *file_transfers; time_t idle; time_t old_idle; /** When we last pinged the server, so we don't ping more * often than once every minute. */ time_t last_ping; JabberID *user; JabberBuddy *user_jb; PurpleConnection *gc; PurpleSslConnection *gsc; gboolean registration; char *initial_avatar_hash; char *avatar_hash; GSList *pending_avatar_requests; GSList *pending_buddy_info_requests; PurpleCircBuffer *write_buffer; guint writeh; gboolean reinit; JabberCapabilities server_caps; gboolean googletalk; char *server_name; char *gmail_last_time; char *gmail_last_tid; char *serverFQDN; #ifdef HAVE_CYRUS_SASL sasl_conn_t *sasl; sasl_callback_t *sasl_cb; sasl_secret_t *sasl_secret; const char *current_mech; int auth_fail_count; int sasl_state; int sasl_maxbuf; GString *sasl_mechs; #endif gboolean unregistration; PurpleAccountUnregistrationCb unregistration_cb; void *unregistration_user_data; gboolean vcard_fetched; /* Timer at login to push updated avatar */ guint vcard_timer; /* Entity Capabilities hash */ char *caps_hash; /* does the local server support PEP? */ gboolean pep; /* Is Buzz enabled? */ gboolean allowBuzz; /* A list of JabberAdHocCommands supported by the server */ GList *commands; /* last presence update to check for differences */ JabberBuddyState old_state; char *old_msg; int old_priority; char *old_avatarhash; /* same for user tune */ char *old_artist; char *old_title; char *old_source; char *old_uri; int old_length; char *old_track; char *certificate_CN; /* A purple timeout tag for the keepalive */ guint keepalive_timeout; guint max_inactivity; guint inactivity_timer; PurpleSrvResponse *srv_rec; guint srv_rec_idx; guint max_srv_rec_idx; /* BOSH stuff */ PurpleBOSHConnection *bosh; /** * This linked list contains PurpleUtilFetchUrlData structs * for when we lookup buddy icons from a url */ GSList *url_datas; /* keep a hash table of JingleSessions */ GHashTable *sessions; /* maybe this should only be present when USE_VV? */ gchar *stun_ip; int stun_port; PurpleDnsQueryData *stun_query; /* stuff for Google's relay handling */ gchar *google_relay_token; gchar *google_relay_host; GList *google_relay_requests; /* the HTTP requests to get */ /* relay info */ /* facebook quirks */ gboolean facebook_roster_cleanup_performed; }; typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *namespace); typedef struct _JabberFeature { gchar *namespace; JabberFeatureEnabled *is_enabled; } JabberFeature; typedef struct _JabberIdentity { gchar *category; gchar *type; gchar *name; gchar *lang; } JabberIdentity; typedef struct _JabberBytestreamsStreamhost { char *jid; char *host; int port; char *zeroconf; } JabberBytestreamsStreamhost; /* what kind of additional features as returned from disco#info are supported? */ extern GList *jabber_features; /* A sorted list of identities advertised. Use jabber_add_identity to add * so it remains sorted. */ extern GList *jabber_identities; void jabber_stream_features_parse(JabberStream *js, xmlnode *packet); void jabber_process_packet(JabberStream *js, xmlnode **packet); void jabber_send(JabberStream *js, xmlnode *data); void jabber_send_raw(JabberStream *js, const char *data, int len); void jabber_send_signal_cb(PurpleConnection *pc, xmlnode **packet, gpointer unused); void jabber_stream_set_state(JabberStream *js, JabberStreamState state); void jabber_register_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *query); void jabber_register_start(JabberStream *js); char *jabber_get_next_id(JabberStream *js); /** Parse an error into a human-readable string and optionally a disconnect * reason. * @param js the stream on which the error occurred. * @param packet the error packet * @param reason where to store the disconnection reason, or @c NULL if you * don't care or you don't intend to close the connection. */ char *jabber_parse_error(JabberStream *js, xmlnode *packet, PurpleConnectionError *reason); /** * Add a feature to the list of features advertised via disco#info. If you * call this while accounts are connected, Bad Things(TM) will happen because * the Entity Caps hash will be out-of-date (which should be fixed :/) * * @param namespace The namespace of the feature * @param cb A callback determining whether or not this feature * will advertised; may be NULL. */ void jabber_add_feature(const gchar *namespace, JabberFeatureEnabled cb); void jabber_remove_feature(const gchar *namespace); /** Adds an identity to this jabber library instance. For list of valid values * visit the website of the XMPP Registrar * (http://www.xmpp.org/registrar/disco-categories.html#client). * * Like with jabber_add_feature, if you call this while accounts are connected, * Bad Things will happen. * * @param category the category of the identity. * @param type the type of the identity. * @param language the language localization of the name. Can be NULL. * @param name the name of the identity. */ void jabber_add_identity(const gchar *category, const gchar *type, const gchar *lang, const gchar *name); /** * GCompareFunc for JabberIdentity structs. */ gint jabber_identity_compare(gconstpointer a, gconstpointer b); /** * Returns true if this connection is over a secure (SSL) stream. Use this * instead of checking js->gsc because BOSH stores its PurpleSslConnection * members in its own data structure. */ gboolean jabber_stream_is_ssl(JabberStream *js); /** * Restart the "we haven't sent anything in a while and should send * something or the server will kick us off" timer (obviously * called when sending something. It's exposed for BOSH.) */ void jabber_stream_restart_inactivity_timer(JabberStream *js); /** PRPL functions */ const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b); const char* jabber_list_emblem(PurpleBuddy *b); char *jabber_status_text(PurpleBuddy *b); void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full); GList *jabber_status_types(PurpleAccount *account); void jabber_login(PurpleAccount *account); void jabber_close(PurpleConnection *gc); void jabber_idle_set(PurpleConnection *gc, int idle); void jabber_blocklist_parse_push(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *child); void jabber_request_block_list(JabberStream *js); void jabber_add_deny(PurpleConnection *gc, const char *who); void jabber_rem_deny(PurpleConnection *gc, const char *who); void jabber_keepalive(PurpleConnection *gc); void jabber_register_gateway(JabberStream *js, const char *gateway); void jabber_register_account(PurpleAccount *account); void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data); gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code); GList *jabber_attention_types(PurpleAccount *account); void jabber_convo_closed(PurpleConnection *gc, const char *who); PurpleChat *jabber_find_blist_chat(PurpleAccount *account, const char *name); gboolean jabber_offline_message(const PurpleBuddy *buddy); int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len); GList *jabber_actions(PurplePlugin *plugin, gpointer context); gboolean jabber_audio_enabled(JabberStream *js, const char *unused); gboolean jabber_video_enabled(JabberStream *js, const char *unused); gboolean jabber_initiate_media(PurpleAccount *account, const char *who, PurpleMediaSessionType type); PurpleMediaCaps jabber_get_media_caps(PurpleAccount *account, const char *who); gboolean jabber_can_receive_file(PurpleConnection *gc, const gchar *who); void jabber_plugin_init(PurplePlugin *plugin); void jabber_plugin_uninit(PurplePlugin *plugin); #endif /* PURPLE_JABBER_H_ */ carbons-0.2.3/headers/jabber/jutil.h000077500000000000000000000065411377140047700173260ustar00rootroot00000000000000/** * @file jutil.h utility functions * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_JUTIL_H_ #define PURPLE_JABBER_JUTIL_H_ typedef struct _JabberID { char *node; char *domain; char *resource; } JabberID; typedef enum { JABBER_BUDDY_STATE_UNKNOWN = -2, JABBER_BUDDY_STATE_ERROR = -1, JABBER_BUDDY_STATE_UNAVAILABLE = 0, JABBER_BUDDY_STATE_ONLINE, JABBER_BUDDY_STATE_CHAT, JABBER_BUDDY_STATE_AWAY, JABBER_BUDDY_STATE_XA, JABBER_BUDDY_STATE_DND } JabberBuddyState; #include "jabber.h" JabberID* jabber_id_new(const char *str); /** * Compare two JIDs for equality. In addition to the node and domain, * the resources of the two JIDs must also be equal (or both absent). */ gboolean jabber_id_equal(const JabberID *jid1, const JabberID *jid2); void jabber_id_free(JabberID *jid); char *jabber_get_domain(const char *jid); char *jabber_get_resource(const char *jid); char *jabber_get_bare_jid(const char *jid); char *jabber_id_get_bare_jid(const JabberID *jid); char *jabber_id_get_full_jid(const JabberID *jid); JabberID *jabber_id_to_bare_jid(const JabberID *jid); gboolean jabber_jid_is_domain(const char *jid); const char *jabber_normalize(const PurpleAccount *account, const char *in); /* Returns true if JID is the bare JID of our server. */ gboolean jabber_is_own_server(JabberStream *js, const char *jid); /* Returns true if JID is the bare JID of our account. */ gboolean jabber_is_own_account(JabberStream *js, const char *jid); gboolean jabber_nodeprep_validate(const char *); gboolean jabber_domain_validate(const char *); gboolean jabber_resourceprep_validate(const char *); /** * Apply the SASLprep profile of stringprep to the string passed in. * * @returns A newly allocated string containing the normalized version * of the input, or NULL if an error occurred (the string could * not be normalized) */ char *jabber_saslprep(const char *); /* state -> readable name */ const char *jabber_buddy_state_get_name(JabberBuddyState state); /* state -> core id */ const char *jabber_buddy_state_get_status_id(JabberBuddyState state); /* state -> show attr (for presence stanza) */ const char *jabber_buddy_state_get_show(JabberBuddyState state); /* core id -> state */ JabberBuddyState jabber_buddy_status_id_get_state(const char *id); /* show attr (presence stanza) -> state */ JabberBuddyState jabber_buddy_show_get_state(const char *id); char *jabber_calculate_data_hash(gconstpointer data, size_t len, const gchar *hash_algo); #endif /* PURPLE_JABBER_JUTIL_H_ */ carbons-0.2.3/headers/jabber/message.h000077500000000000000000000045501377140047700176210ustar00rootroot00000000000000/** * @file message.h Message handlers * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_MESSAGE_H_ #define PURPLE_JABBER_MESSAGE_H_ #include "buddy.h" #include "jabber.h" #include "xmlnode.h" typedef struct _JabberMessage { JabberStream *js; enum { JABBER_MESSAGE_NORMAL, JABBER_MESSAGE_CHAT, JABBER_MESSAGE_GROUPCHAT, JABBER_MESSAGE_HEADLINE, JABBER_MESSAGE_ERROR, JABBER_MESSAGE_GROUPCHAT_INVITE, JABBER_MESSAGE_EVENT, JABBER_MESSAGE_OTHER } type; time_t sent; gboolean delayed; gboolean hasBuzz; char *id; char *from; char *to; char *subject; char *body; char *xhtml; char *password; char *error; char *thread_id; enum { JM_STATE_NONE, JM_STATE_ACTIVE, JM_STATE_COMPOSING, JM_STATE_PAUSED, JM_STATE_INACTIVE, JM_STATE_GONE } chat_state; GList *etc; GList *eventitems; } JabberMessage; void jabber_message_free(JabberMessage *jm); void jabber_message_send(JabberMessage *jm); void jabber_message_parse(JabberStream *js, xmlnode *packet); int jabber_message_send_im(PurpleConnection *gc, const char *who, const char *msg, PurpleMessageFlags flags); int jabber_message_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags); unsigned int jabber_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state); gboolean jabber_buzz_isenabled(JabberStream *js, const gchar *namespace); gboolean jabber_custom_smileys_isenabled(JabberStream *js, const const gchar *namespace); #endif /* PURPLE_JABBER_MESSAGE_H_ */ carbons-0.2.3/headers/jabber/namespaces.h000077500000000000000000000101521377140047700203070ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_NAMESPACES_H_ #define PURPLE_JABBER_NAMESPACES_H_ #define NS_XMPP_BIND "urn:ietf:params:xml:ns:xmpp-bind" #define NS_XMPP_CLIENT "jabber:client" #define NS_XMPP_SASL "urn:ietf:params:xml:ns:xmpp-sasl" #define NS_XMPP_SESSION "urn:ietf:params:xml:ns:xmpp-session" #define NS_XMPP_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" #define NS_XMPP_STREAMS "http://etherx.jabber.org/streams" #define NS_XMPP_TLS "urn:ietf:params:xml:ns:xmpp-tls" /* XEP-0012 Last Activity (and XEP-0256 Last Activity in Presence) */ #define NS_LAST_ACTIVITY "jabber:iq:last" /* XEP-0030 Service Discovery */ #define NS_DISCO_INFO "http://jabber.org/protocol/disco#info" #define NS_DISCO_ITEMS "http://jabber.org/protocol/disco#items" /* XEP-0047 IBB (In-band bytestreams) */ #define NS_IBB "http://jabber.org/protocol/ibb" /* XEP-0065 SOCKS5 Bytestreams */ #define NS_BYTESTREAMS "http://jabber.org/protocol/bytestreams" /* XEP-0066 Out of Band Data (OOB) */ #define NS_OOB_IQ_DATA "jabber:iq:oob" #define NS_OOB_X_DATA "jabber:x:oob" /* XEP-0071 XHTML-IM (rich-text messages) */ #define NS_XHTML_IM "http://jabber.org/protocol/xhtml-im" #define NS_XHTML "http://www.w3.org/1999/xhtml" /* XEP-0084 v0.12 User Avatar */ #define NS_AVATAR_0_12_DATA "http://www.xmpp.org/extensions/xep-0084.html#ns-data" #define NS_AVATAR_0_12_METADATA "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata" /* XEP-0084 v1.1 User Avatar */ #define NS_AVATAR_1_1_DATA "urn:xmpp:avatar:data" #define NS_AVATAR_1_1_METADATA "urn:xmpp:avatar:metadata" /* XEP-0096 SI File Transfer */ #define NS_SI_FILE_TRANSFER "http://jabber.org/protocol/si/profile/file-transfer" /* XEP-0124 Bidirectional-streams Over Synchronous HTTP (BOSH) */ #define NS_BOSH "http://jabber.org/protocol/httpbind" /* XEP-0191 Simple Communications Blocking */ #define NS_SIMPLE_BLOCKING "urn:xmpp:blocking" /* XEP-0199 Ping */ #define NS_PING "urn:xmpp:ping" /* XEP-0202 Entity Time */ #define NS_ENTITY_TIME "urn:xmpp:time" /* XEP-0203 Delayed Delivery (and legacy delayed delivery) */ #define NS_DELAYED_DELIVERY "urn:xmpp:delay" #define NS_DELAYED_DELIVERY_LEGACY "jabber:x:delay" /* XEP-0206 XMPP over BOSH */ #define NS_XMPP_BOSH "urn:xmpp:xbosh" /* XEP-0224 Attention */ #define NS_ATTENTION "urn:xmpp:attention:0" /* XEP-0231 BoB (Bits of Binary) */ #define NS_BOB "urn:xmpp:bob" /* XEP-0237 Roster Versioning */ #define NS_ROSTER_VERSIONING "urn:xmpp:features:rosterver" /* XEP-0264 File Transfer Thumbnails (Thumbs) */ #define NS_THUMBS "urn:xmpp:thumbs:0" /* Google extensions */ #define NS_GOOGLE_CAMERA "http://www.google.com/xmpp/protocol/camera/v1" #define NS_GOOGLE_VIDEO "http://www.google.com/xmpp/protocol/video/v1" #define NS_GOOGLE_VOICE "http://www.google.com/xmpp/protocol/voice/v1" #define NS_GOOGLE_JINGLE_INFO "google:jingleinfo" #define NS_GOOGLE_MAIL_NOTIFY "google:mail:notify" #define NS_GOOGLE_ROSTER "google:roster" #define NS_GOOGLE_PROTOCOL_SESSION "http://www.google.com/xmpp/protocol/session" #define NS_GOOGLE_SESSION "http://www.google.com/session" #define NS_GOOGLE_SESSION_PHONE "http://www.google.com/session/phone" #define NS_GOOGLE_SESSION_VIDEO "http://www.google.com/session/video" #endif /* PURPLE_JABBER_NAMESPACES_H_ */ carbons-0.2.3/headers/jabber/oob.h000077500000000000000000000023051377140047700167500ustar00rootroot00000000000000/** * @file oob.h out-of-band transfer functions * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_OOB_H_ #define PURPLE_JABBER_OOB_H_ #include "jabber.h" void jabber_oob_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *querynode); #endif /* PURPLE_JABBER_OOB_H_ */ carbons-0.2.3/headers/jabber/parser.h000077500000000000000000000023361377140047700174710ustar00rootroot00000000000000/** * @file parser.h XML parser functions * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_PARSER_H_ #define PURPLE_JABBER_PARSER_H_ #include "jabber.h" void jabber_parser_setup(JabberStream *js); void jabber_parser_free(JabberStream *js); void jabber_parser_process(JabberStream *js, const char *buf, int len); #endif /* PURPLE_JABBER_PARSER_H_ */ carbons-0.2.3/headers/jabber/pep.h000077500000000000000000000065161377140047700167650ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_PEP_H_ #define PURPLE_JABBER_PEP_H_ #include "jabber.h" #include "message.h" #include "buddy.h" void jabber_pep_init(void); void jabber_pep_uninit(void); void jabber_pep_init_actions(GList **m); /* * Callback for receiving PEP events. * * @parameter js The JabberStream this item was received on * @parameter items The <items/>-tag with the <item/>-children */ typedef void (JabberPEPHandler)(JabberStream *js, const char *from, xmlnode *items); /* * Registers a callback for PEP events. Also automatically announces this receiving capability via disco#info. * Don't forget to use jabber_add_feature when supporting the sending of PEP events of this type. * * @parameter xmlns The namespace for this event * @parameter handlerfunc The callback to be used when receiving an event with this namespace */ void jabber_pep_register_handler(const char *xmlns, JabberPEPHandler handlerfunc); /* * Request a specific item from another PEP node. * * @parameter js The JabberStream that should be used * @parameter to The target PEP node * @parameter node The node name of the item that is requested * @parameter id The item id of the requested item (may be NULL) * @parameter cb The callback to be used when this item is received * * The items element passed to the callback will be NULL if any error occurred (like a permission error, node doesn't exist etc.) */ void jabber_pep_request_item(JabberStream *js, const char *to, const char *node, const char *id, JabberPEPHandler cb); /* * Default callback that can be used for namespaces which should only be enabled when PEP is supported * * @parameter js The JabberStream struct for this connection * @parameter namespace The namespace that's queried, ignored. * * @returns TRUE when PEP is enabled, FALSE otherwise */ gboolean jabber_pep_namespace_only_when_pep_enabled_cb(JabberStream *js, const gchar *namespace); void jabber_handle_event(JabberMessage *jm); /** * Delete the specified PEP node. */ void jabber_pep_delete_node(JabberStream *js, const gchar *node); /* * Publishes PEP item(s) * * @parameter js The JabberStream associated with the connection this event should be published * @parameter publish The publish node. This could be for example <publish node='http://jabber.org/protocol/tune'/> with an <item/> as subnode */ void jabber_pep_publish(JabberStream *js, xmlnode *publish); #endif /* PURPLE_JABBER_PEP_H_ */ carbons-0.2.3/headers/jabber/ping.h000077500000000000000000000025021377140047700171250ustar00rootroot00000000000000/** * @file ping.h ping functions * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_PING_H_ #define PURPLE_JABBER_PING_H_ #include "jabber.h" #include "iq.h" #include "xmlnode.h" void jabber_ping_parse(JabberStream *js, const char *from, JabberIqType, const char *id, xmlnode *child); gboolean jabber_ping_jid(JabberStream *js, const char *jid); void jabber_keepalive_ping(JabberStream *js); #endif /* PURPLE_JABBER_PING_H_ */ carbons-0.2.3/headers/jabber/presence.h000077500000000000000000000063211377140047700177770ustar00rootroot00000000000000/** * @file presence.h Presence * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_PRESENCE_H_ #define PURPLE_JABBER_PRESENCE_H_ typedef enum { JABBER_PRESENCE_ERROR = -2, JABBER_PRESENCE_PROBE = -1, JABBER_PRESENCE_AVAILABLE, JABBER_PRESENCE_UNAVAILABLE, JABBER_PRESENCE_SUBSCRIBE, JABBER_PRESENCE_SUBSCRIBED, JABBER_PRESENCE_UNSUBSCRIBE, JABBER_PRESENCE_UNSUBSCRIBED } JabberPresenceType; typedef struct _JabberPresenceChatInfo JabberPresenceChatInfo; typedef struct _JabberPresence JabberPresence; #include "buddy.h" #include "chat.h" #include "jabber.h" #include "jutil.h" #include "xmlnode.h" struct _JabberPresenceChatInfo { GSList *codes; xmlnode *item; }; struct _JabberPresence { JabberPresenceType type; JabberID *jid_from; const char *from; const char *to; const char *id; JabberBuddy *jb; JabberChat *chat; JabberPresenceChatInfo chat_info; xmlnode *caps; /* TODO: Temporary, see presence.c:parse_caps */ JabberBuddyState state; gchar *status; int priority; char *vcard_avatar_hash; char *nickname; gboolean delayed; time_t sent; int idle; }; typedef void (JabberPresenceHandler)(JabberStream *js, JabberPresence *presence, xmlnode *child); void jabber_presence_register_handler(const char *node, const char *xmlns, JabberPresenceHandler *handler); void jabber_presence_init(void); void jabber_presence_uninit(void); void jabber_set_status(PurpleAccount *account, PurpleStatus *status); /** * Send a full presence stanza. * * @param js A JabberStream object. * @param force Force sending the presence stanza, irrespective of whether * the contents seem to have changed. */ void jabber_presence_send(JabberStream *js, gboolean force); xmlnode *jabber_presence_create(JabberBuddyState state, const char *msg, int priority); /* DEPRECATED */ xmlnode *jabber_presence_create_js(JabberStream *js, JabberBuddyState state, const char *msg, int priority); void jabber_presence_parse(JabberStream *js, xmlnode *packet); void jabber_presence_subscription_set(JabberStream *js, const char *who, const char *type); void jabber_presence_fake_to_self(JabberStream *js, PurpleStatus *status); void purple_status_to_jabber(const PurpleStatus *status, JabberBuddyState *state, char **msg, int *priority); #endif /* PURPLE_JABBER_PRESENCE_H_ */ carbons-0.2.3/headers/jabber/roster.h000077500000000000000000000036371377140047700175200ustar00rootroot00000000000000/** * @file roster.h Roster manipulation * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_ROSTER_H_ #define PURPLE_JABBER_ROSTER_H_ /* it must *not* be localized */ #define JABBER_ROSTER_DEFAULT_GROUP "Buddies" #include "jabber.h" void jabber_roster_request(JabberStream *js); void jabber_roster_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *query); void jabber_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); void jabber_roster_alias_change(PurpleConnection *gc, const char *name, const char *alias); void jabber_roster_group_change(PurpleConnection *gc, const char *name, const char *old_group, const char *new_group); void jabber_roster_group_rename(PurpleConnection *gc, const char *old_name, PurpleGroup *group, GList *moved_buddies); void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group); const gchar * jabber_roster_group_get_global_name(PurpleGroup *group); #endif /* PURPLE_JABBER_ROSTER_H_ */ carbons-0.2.3/headers/jabber/si.h000077500000000000000000000030461377140047700166070ustar00rootroot00000000000000/** * @file si.h SI transfer functions * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_SI_H_ #define PURPLE_JABBER_SI_H_ #include "ft.h" #include "jabber.h" void jabber_bytestreams_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *query); void jabber_si_parse(JabberStream *js, const char *from, JabberIqType type, const char *id, xmlnode *si); PurpleXfer *jabber_si_new_xfer(PurpleConnection *gc, const char *who); void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file); void jabber_si_init(void); void jabber_si_uninit(void); #endif /* PURPLE_JABBER_SI_H_ */ carbons-0.2.3/headers/jabber/useravatar.h000077500000000000000000000024131377140047700203460ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef _PURPLE_JABBER_USERAVATAR_H_ #define _PURPLE_JABBER_USERAVATAR_H_ #include "jabber.h" #include "imgstore.h" /* Implementation of XEP-0084 */ void jabber_avatar_init(void); void jabber_avatar_set(JabberStream *js, PurpleStoredImage *img); void jabber_avatar_fetch_mine(JabberStream *js); #endif /* _PURPLE_JABBER_USERAVATAR_H_ */ carbons-0.2.3/headers/jabber/usermood.h000077500000000000000000000025261377140047700200330ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_USERMOOD_H_ #define PURPLE_JABBER_USERMOOD_H_ #include "jabber.h" /* Implementation of XEP-0107 */ void jabber_mood_init(void); void jabber_mood_set(JabberStream *js, const char *mood, /* must be one of the valid strings defined in the XEP */ const char *text /* might be NULL */); PurpleMood *jabber_get_moods(PurpleAccount *account); #endif /* PURPLE_JABBER_USERMOOD_H_ */ carbons-0.2.3/headers/jabber/usernick.h000077500000000000000000000022371377140047700200200ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_USERNICK_H_ #define PURPLE_JABBER_USERNICK_H_ #include "jabber.h" /* Implementation of XEP-0172 */ void jabber_nick_init(void); void jabber_nick_init_action(GList **m); #endif /* PURPLE_JABBER_USERNICK_H_ */ carbons-0.2.3/headers/jabber/usertune.h000077500000000000000000000027411377140047700200470ustar00rootroot00000000000000/* * purple - Jabber Protocol Plugin * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 * */ #ifndef PURPLE_JABBER_USERTUNE_H_ #define PURPLE_JABBER_USERTUNE_H_ #include "jabber.h" /* Implementation of XEP-0118 */ typedef struct _PurpleJabberTuneInfo PurpleJabberTuneInfo; struct _PurpleJabberTuneInfo { char *artist; char *title; char *album; char *track; /* either the index of the track in the album or the URL for a stream */ int time; /* in seconds, -1 for unknown */ char *url; }; void jabber_tune_init(void); void jabber_tune_set(PurpleConnection *gc, const PurpleJabberTuneInfo *tuneinfo); #endif /* PURPLE_JABBER_USERTUNE_H_ */ carbons-0.2.3/headers/jabber/xdata.h000077500000000000000000000041661377140047700173010ustar00rootroot00000000000000/** * @file xdata.h utility functions * * purple * * Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * source distribution. * * 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 */ #ifndef PURPLE_JABBER_XDATA_H_ #define PURPLE_JABBER_XDATA_H_ #include "jabber.h" #include "xmlnode.h" typedef struct _JabberXDataAction { char *name; char *handle; } JabberXDataAction; typedef void (*jabber_x_data_cb)(JabberStream *js, xmlnode *result, gpointer user_data); typedef void (*jabber_x_data_action_cb)(JabberStream *js, xmlnode *result, const char *actionhandle, gpointer user_data); void *jabber_x_data_request(JabberStream *js, xmlnode *packet, jabber_x_data_cb cb, gpointer user_data); void *jabber_x_data_request_with_actions(JabberStream *js, xmlnode *packet, GList *actions, int defaultaction, jabber_x_data_action_cb cb, gpointer user_data); /* * Return the form type (the CDATA of the value child of the FORM_TYPE * field entry. * E.g., for the following, "http://jabber.org/protocol/muc#roominfo". * * * http://jabber.org/protocol/muc#roominfo * * * * @param form The xmlnode for the form (the 'x' element) * @returns The FORM_TYPE. Must be freed by caller. */ gchar *jabber_x_data_get_formtype(const xmlnode *form); #endif /* PURPLE_JABBER_XDATA_H_ */ carbons-0.2.3/src/000077500000000000000000000000001377140047700137445ustar00rootroot00000000000000carbons-0.2.3/src/carbons.c000066400000000000000000000301141377140047700155360ustar00rootroot00000000000000/* carbons - XEP-0280 plugin for libpurple Copyright (C) 2017, Richard Bayerle 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 02110-1301, USA. */ #include #include #include #include #include "iq.h" #include "carbons.h" #include "carbons_internal.h" #define JABBER_PROTOCOL_ID "prpl-jabber" #define CARBONS_SETTING_NAME "carbons-enabled" #define CARBONS_LOG_CATEGORY "carbons" #define CARBONS_XMLNS "urn:xmpp:carbons:2" // https://xmpp.org/extensions/xep-0280.html #define DISCO_XMLNS "http://jabber.org/protocol/disco#info" // see XEP-0030: Service Discovery (https://xmpp.org/extensions/xep-0030.html) /** * From section 11, security considerations: * 'Any forwarded copies received by a Carbons-enabled client MUST be from that user's bare JID' * * If there was an attempt to fake a message, this function will return 0 and delete all children. * Otherwise it just returns 1. */ static int carbons_filter_invalid(PurpleAccount * acc_p, xmlnode * outer_msg_stanza_p) { char ** split = (void *) 0; xmlnode * curr_node_p = (void *) 0; xmlnode * temp_node_p = (void *) 0; int ret_val = 0; split = g_strsplit(purple_account_get_username(acc_p), "/", 2); if (g_strcmp0(split[0], xmlnode_get_attrib(outer_msg_stanza_p, "from"))) { purple_debug_warning(CARBONS_LOG_CATEGORY, "Invalid sender: %s (should be: %s)\n", xmlnode_get_attrib(outer_msg_stanza_p, "from"), split[0]); curr_node_p = outer_msg_stanza_p->child; while(curr_node_p) { temp_node_p = curr_node_p->next; xmlnode_free(curr_node_p); curr_node_p = temp_node_p; } ret_val = 0; } else { ret_val = 1; } g_strfreev(split); return ret_val; } void carbons_xml_received_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp) { xmlnode * carbons_node_p = (void *) 0; xmlnode * forwarded_node_p = (void *) 0; xmlnode * msg_node_p = (void *) 0; if (!stanza_pp || !(*stanza_pp)) { return; } if (g_strcmp0((*stanza_pp)->name, "message")) { return; } carbons_node_p = xmlnode_get_child_with_namespace(*stanza_pp, "received", CARBONS_XMLNS); if (carbons_node_p) { purple_debug_info(CARBONS_LOG_CATEGORY, "Received carbon copy of a received message.\n"); if (!carbons_filter_invalid(purple_connection_get_account(gc_p), *stanza_pp)) { purple_debug_warning(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of received message with invalid sender.\n"); return; } forwarded_node_p = xmlnode_get_child(carbons_node_p, "forwarded"); if (!forwarded_node_p) { purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of received message that does not contain a 'forwarded' node.\n"); return; } msg_node_p = xmlnode_get_child(forwarded_node_p, "message"); if (!msg_node_p) { purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of received message that does not contain a 'message' node.\n"); return; } msg_node_p = xmlnode_copy(msg_node_p); xmlnode_free(*stanza_pp); *stanza_pp = msg_node_p; return; } carbons_node_p = xmlnode_get_child_with_namespace(*stanza_pp, "sent", CARBONS_XMLNS); if (carbons_node_p) { purple_debug_info(CARBONS_LOG_CATEGORY, "Received carbon copy of a sent message.\n"); if (!carbons_filter_invalid(purple_connection_get_account(gc_p), *stanza_pp)) { purple_debug_warning(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of sent message with invalid sender.\n"); return; } forwarded_node_p = xmlnode_get_child(carbons_node_p, "forwarded"); if (!forwarded_node_p) { purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of sent message that does not contain a 'forwarded' node.\n"); return; } msg_node_p = xmlnode_get_child(forwarded_node_p, "message"); if (!msg_node_p) { purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of sent message that does not contain a 'message' node.\n"); return; } // add an empty node inside the message node for detection in later callback carbons_node_p = xmlnode_new_child(msg_node_p, "sent"); xmlnode_set_namespace(carbons_node_p, CARBONS_XMLNS); purple_debug_info(CARBONS_LOG_CATEGORY, "Stripped carbons envelope of a sent message and passing through the message stanza.\n"); msg_node_p = xmlnode_copy(msg_node_p); xmlnode_free(*stanza_pp); *stanza_pp = msg_node_p; } } // libpurple doesn't know what to do with incoming messages addressed to someone else, so they need to be written to the conversation manually // checks for presence of a node that was inserted in the initial handler void carbons_xml_stripped_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp) { xmlnode * carbons_node_p = (void *) 0; xmlnode * body_node_p = (void *) 0; char * buddy_name_bare = (void *) 0; PurpleConversation * conv_p = (void *) 0; PurpleAccount * acc_p = (void *) 0; char * body_data = (void *) 0; if (!stanza_pp || !(*stanza_pp)) { return; } if (g_strcmp0((*stanza_pp)->name, "message")) { return; } carbons_node_p = xmlnode_get_child_with_namespace(*stanza_pp, "sent", CARBONS_XMLNS); if (!carbons_node_p) { return; } body_node_p = xmlnode_get_child(*stanza_pp, "body"); if (!body_node_p) { return; } buddy_name_bare = jabber_get_bare_jid(xmlnode_get_attrib(*stanza_pp, "to")); acc_p = purple_connection_get_account(gc_p); conv_p = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy_name_bare, acc_p); if (!conv_p) { conv_p = purple_conversation_new(PURPLE_CONV_TYPE_IM, acc_p, buddy_name_bare); } purple_debug_info(CARBONS_LOG_CATEGORY, "Writing body of the carbon copy of a sent message to the conversation window with %s.\n", buddy_name_bare); body_data = xmlnode_get_data(body_node_p); purple_conversation_write(conv_p, xmlnode_get_attrib(*stanza_pp, "from"), body_data, PURPLE_MESSAGE_SEND, time((void *) 0)); xmlnode_free(body_node_p); xmlnode_free(carbons_node_p); g_free(body_data); g_free(buddy_name_bare); } void carbons_enable_cb(JabberStream * js_p, const char * from, JabberIqType type, const char * id, xmlnode * packet_p, gpointer data_p) { const char * accname = purple_account_get_username(purple_connection_get_account(js_p->gc)); if (type == JABBER_IQ_ERROR) { purple_debug_error(CARBONS_LOG_CATEGORY, "Server returned an error when trying to activate carbons for %s.\n", accname); } else { purple_debug_info(CARBONS_LOG_CATEGORY, "Successfully activated carbons for %s.\n", accname); } } void carbons_discover_cb(JabberStream * js_p, const char * from, JabberIqType type, const char * id, xmlnode * packet_p, gpointer data_p) { xmlnode * query_node_p = (void *) 0; xmlnode * child_node_p = (void *) 0; JabberIq * jiq_p = (void *) 0; xmlnode * req_node_p = (void *) 0; const char * feature_name = (void *) 0; const char * accname = purple_account_get_username(purple_connection_get_account(js_p->gc)); if (type == JABBER_IQ_ERROR) { purple_debug_error(CARBONS_LOG_CATEGORY, "Server returned an error when trying to discover carbons for %s.\n", accname); return; } query_node_p = xmlnode_get_child_with_namespace(packet_p, "query", DISCO_XMLNS); if (!query_node_p) { purple_debug_error(CARBONS_LOG_CATEGORY, "No 'query' node in feature discovery reply for %s.\n", accname); return; } for (child_node_p = query_node_p->child; child_node_p; child_node_p = child_node_p->next) { if (g_strcmp0(child_node_p->name, "feature")) { continue; } feature_name = xmlnode_get_attrib(child_node_p, "var"); if (!g_strcmp0(CARBONS_XMLNS, feature_name)) { purple_debug_info(CARBONS_LOG_CATEGORY, "Found carbons in server features, sending enable request for %s.\n", accname); jiq_p = jabber_iq_new(js_p, JABBER_IQ_SET); req_node_p = xmlnode_new_child(jiq_p->node, "enable"); xmlnode_set_namespace(req_node_p, CARBONS_XMLNS); jabber_iq_set_callback(jiq_p, carbons_enable_cb, (void *) 0); jabber_iq_send(jiq_p); purple_debug_info(CARBONS_LOG_CATEGORY, "Sent enable request for %s.\n", accname); return; } } purple_debug_info(CARBONS_LOG_CATEGORY, "Server does not support message carbons, therefore doing nothing for %s.\n", accname); } void carbons_account_connect_cb(PurpleAccount * acc_p) { if (strcmp(purple_account_get_protocol_id(acc_p), JABBER_PROTOCOL_ID)) { return; } // "migration code" - remove obsolete setting purple_account_remove_setting(acc_p, CARBONS_SETTING_NAME); // send discovery request JabberIq * jiq_p = (void *) 0; xmlnode * query_node_p = (void *) 0; JabberStream * js_p = purple_connection_get_protocol_data(purple_account_get_connection(acc_p)); jiq_p = jabber_iq_new(js_p, JABBER_IQ_GET); xmlnode_set_attrib(jiq_p->node, "to", js_p->user->domain); query_node_p = xmlnode_new_child(jiq_p->node, "query"); xmlnode_set_namespace(query_node_p, DISCO_XMLNS); jabber_iq_set_callback(jiq_p, carbons_discover_cb, (void *) 0); jabber_iq_send(jiq_p); purple_debug_info(CARBONS_LOG_CATEGORY, "Sent feature discovery request for %s.\n", purple_account_get_username(acc_p)); } gboolean carbons_plugin_load(PurplePlugin * plugin_p) { GList * accs_l_p = (void *) 0; GList * curr_p = (void *) 0; PurpleAccount * acc_p = (void *) 0; int some_acc_is_connected = 0; // manually call init code if there are already accounts connected, e.g. when plugin is loaded manually accs_l_p = purple_accounts_get_all_active(); for (curr_p = accs_l_p; curr_p; curr_p = curr_p->next) { acc_p = (PurpleAccount *) curr_p->data; if (purple_account_is_connected(acc_p)) { some_acc_is_connected = 1; carbons_account_connect_cb(acc_p); } } if(!some_acc_is_connected) { // according to the docs, Bad Things(TM) will happen if this is called while accounts are connected (void) jabber_add_feature(CARBONS_XMLNS, (void *) 0); } (void) purple_signal_connect(purple_accounts_get_handle(), "account-signed-on", plugin_p, PURPLE_CALLBACK(carbons_account_connect_cb), NULL); (void) purple_signal_connect_priority(purple_plugins_find_with_id(JABBER_PROTOCOL_ID), "jabber-receiving-xmlnode", plugin_p, PURPLE_CALLBACK(carbons_xml_received_cb), NULL, PURPLE_PRIORITY_LOWEST + 100); (void) purple_signal_connect_priority(purple_plugins_find_with_id(JABBER_PROTOCOL_ID), "jabber-receiving-xmlnode", plugin_p, PURPLE_CALLBACK(carbons_xml_stripped_cb), NULL, PURPLE_PRIORITY_HIGHEST - 50); g_list_free(accs_l_p); return TRUE; } static PurplePluginInfo info = { PURPLE_PLUGIN_MAGIC, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_PLUGIN_STANDARD, NULL, 0, NULL, PURPLE_PRIORITY_DEFAULT, "core-riba-carbons", "XMPP Message Carbons", CARBONS_VERSION, "Implements XEP-0280: Message Carbons as a plugin.", "This plugin enables a consistent history view across multiple devices which are online at the same time.", CARBONS_AUTHOR, "https://github.com/gkdr/carbons", carbons_plugin_load, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static void carbons_plugin_init(PurplePlugin * plugin_p) { PurplePluginInfo * info_p = plugin_p->info; info_p->dependencies = g_list_prepend(info_p->dependencies, JABBER_PROTOCOL_ID); } PURPLE_INIT_PLUGIN(carbons, carbons_plugin_init, info) carbons-0.2.3/src/carbons.h000066400000000000000000000002421377140047700155420ustar00rootroot00000000000000#ifndef __CARBONS_H # define __CARBONS_H # define CARBONS_VERSION "0.2.3" # define CARBONS_AUTHOR "Richard Bayerle " #endif /* __CARBONS_H */ carbons-0.2.3/src/carbons_internal.h000066400000000000000000000014511377140047700174410ustar00rootroot00000000000000#ifndef __CARBONS_INT_H # define __CARBONS_INT_H void carbons_xml_received_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp); void carbons_xml_stripped_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp); void carbons_discover(PurpleAccount * acc_p); void carbons_discover_cb(JabberStream * js_p, const char * from, JabberIqType type, const char * id, xmlnode * packet_p, gpointer data_p); void carbons_enable_cb(JabberStream * js_p, const char * from, JabberIqType type, const char * id, xmlnode * packet_p, gpointer data_p); void carbons_account_connect_cb(PurpleAccount * acc_p); gboolean carbons_plugin_load(PurplePlugin * plugin_p); #endif /* CARBONS_INTERNAL_H */ carbons-0.2.3/test/000077500000000000000000000000001377140047700141345ustar00rootroot00000000000000carbons-0.2.3/test/mocks.c000066400000000000000000000105451377140047700154210ustar00rootroot00000000000000#include #include #include #include #include "jabber.h" #define CARBONS_XMLNS "urn:xmpp:carbons:2" #define DISCO_XMLNS "http://jabber.org/protocol/disco#info" gboolean __wrap_purple_account_is_connected(const PurpleAccount * acc_p) { gboolean connected; connected = mock_type(gboolean); return connected; } const char * __wrap_purple_account_get_protocol_id(const PurpleAccount * acc_p) { check_expected_ptr(acc_p); char * protocol_id; protocol_id = mock_ptr_type(char *); return protocol_id; } char * __wrap_purple_account_get_username(PurpleAccount * acc_p) { char * username; username = mock_ptr_type(char *); return username; } PurpleConnection * __wrap_purple_account_get_connection(PurpleAccount * acc_p) { PurpleConnection * connection_p; connection_p = mock_ptr_type(PurpleConnection *); return connection_p; } PurpleAccount * __wrap_purple_connection_get_account(const PurpleConnection * gc_p) { PurpleAccount * account_p; account_p = mock_ptr_type(PurpleAccount *); return account_p; } void * __wrap_purple_connection_get_protocol_data(const PurpleConnection * connection_p) { JabberStream * js_p; js_p = mock_ptr_type(JabberStream *); return js_p; } void __wrap_jabber_iq_send(JabberIq * iq_p) { check_expected(iq_p->type); check_expected(iq_p->callback); const char * to = xmlnode_get_attrib(iq_p->node, "to"); check_expected(to); xmlnode * query_node_p = xmlnode_get_child_with_namespace(iq_p->node, "query", DISCO_XMLNS); check_expected(query_node_p); xmlnode * enable_node_p = xmlnode_get_child_with_namespace(iq_p->node, "enable", CARBONS_XMLNS); check_expected(enable_node_p); } void __wrap_purple_debug_error(const char * category, const char * format, ...) { function_called(); } void __wrap_purple_debug_warning(const char * category, const char * format, ...) { function_called(); } PurpleConversation * __wrap_purple_find_conversation_with_account(PurpleConversationType type, const char * name, const PurpleAccount *account) { PurpleConversation * pc_p; pc_p = mock_ptr_type(PurpleConversation *); return pc_p; } void __wrap_purple_conversation_write(PurpleConversation * conv_p, const char * who, const char * message, PurpleMessageFlags flags, time_t mtime) { check_expected_ptr(conv_p); check_expected(who); check_expected(message); check_expected(flags); } PurpleConversation * __wrap_purple_conversation_new(PurpleConversationType type, PurpleAccount * account, const char * name) { check_expected(type); check_expected_ptr(account); check_expected(name); PurpleConversation * conv_p; conv_p = mock_ptr_type(PurpleConversation *); return conv_p; } void __wrap_jabber_add_feature(const gchar * namespace, JabberFeatureEnabled cb) { check_expected(namespace); } void * __wrap_purple_accounts_get_handle(void) { void * handle_p; handle_p = mock_ptr_type(void *); return handle_p; } PurplePlugin * __wrap_purple_plugins_find_with_id(const char * id) { check_expected(id); PurplePlugin * plugin_p; plugin_p = mock_ptr_type(PurplePlugin *); return plugin_p; } gulong __wrap_purple_signal_connect(void * instance, const char * signal, void * handle, PurpleCallback func, void * data) { check_expected_ptr(instance); check_expected(signal); check_expected_ptr(handle); check_expected_ptr(func); return 1; // ignored } gulong __wrap_purple_signal_connect_priority(void * instance, const char * signal, void * handle, PurpleCallback func, void * data, int priority) { check_expected_ptr(instance); check_expected(signal); check_expected_ptr(handle); check_expected_ptr(func); check_expected(priority); return 2; // ignored } GList * __wrap_purple_accounts_get_all_active(void) { GList * active_accounts; active_accounts = mock_ptr_type(GList *); return active_accounts; }carbons-0.2.3/test/test_carbons.c000066400000000000000000001150311377140047700167670ustar00rootroot00000000000000#include #include #include #include #include "jabber.h" #include "../src/carbons.h" #include "../src/carbons_internal.h" #include "mocks.c" /** * Shuould send well-formed "enable" request if feature is contained in discovery response. */ static void test_carbons_discover_cb_success(void ** state) { (void) state; const char * test_jid = "romeo@montague.example/garden"; // example from docs const char * reply = "" "" "" "" ""; xmlnode * reply_node_p = xmlnode_from_str(reply, -1); JabberStream * js_p = malloc(sizeof (JabberStream)); js_p->next_id = 1; js_p->user = jabber_id_new(test_jid); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, test_jid); expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); // not set here expect_value(__wrap_jabber_iq_send, to, NULL); expect_value(__wrap_jabber_iq_send, query_node_p, NULL); carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); free(js_p); } /** * Success case with a real world example (reply received from Prosody 0.11.0). */ static void test_carbons_discover_cb_real_world_reply(void ** state) { (void) state; const char * own_jid = "b@localhost/pidgin"; const char * reply = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; xmlnode * reply_node_p = xmlnode_from_str(reply, -1); JabberStream * js_p = malloc(sizeof (JabberStream)); js_p->next_id = 1; js_p->user = jabber_id_new(own_jid); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, own_jid); expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); // not set here expect_value(__wrap_jabber_iq_send, to, NULL); expect_value(__wrap_jabber_iq_send, query_node_p, NULL); carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); free(js_p); } /** * Positive reply and the feature is the first child of the query node. */ static void test_carbons_discover_cb_first_child(void ** state) { (void) state; const char * own_jid = "b@localhost/pidgin"; const char * reply = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; xmlnode * reply_node_p = xmlnode_from_str(reply, -1); JabberStream * js_p = malloc(sizeof (JabberStream)); js_p->next_id = 1; js_p->user = jabber_id_new(own_jid); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, own_jid); expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); // not set here expect_value(__wrap_jabber_iq_send, to, NULL); expect_value(__wrap_jabber_iq_send, query_node_p, NULL); carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); free(js_p); } /** * Positive reply and the feature is the last cild of the query node. */ static void test_carbons_discover_cb_last_child(void ** state) { (void) state; const char * own_jid = "b@localhost/pidgin"; const char * reply = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; xmlnode * reply_node_p = xmlnode_from_str(reply, -1); JabberStream * js_p = malloc(sizeof (JabberStream)); js_p->next_id = 1; js_p->user = jabber_id_new(own_jid); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, own_jid); expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); // not set here expect_value(__wrap_jabber_iq_send, to, NULL); expect_value(__wrap_jabber_iq_send, query_node_p, NULL); carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); free(js_p); } /** * Query successful, but carbons is not contained in the reply. */ static void test_carbons_discover_cb_no_carbons(void ** state) { (void) state; const char * own_jid = "b@localhost/pidgin"; const char * reply = "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""; xmlnode * reply_node_p = xmlnode_from_str(reply, -1); JabberStream * js_p = malloc(sizeof (JabberStream)); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, own_jid); // for now, no idea how to check for "not called", so at least make sure it doesn't crash in this case carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); free(js_p); } /** * Should abort when receiving an error reply. */ static void test_carbons_discover_cb_error(void ** state) { (void) state; const char * test_jid = "romeo@montague.example/garden"; JabberStream * js_p = malloc(sizeof (JabberStream)); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, test_jid); expect_function_call(__wrap_purple_debug_error); carbons_discover_cb(js_p, "from", JABBER_IQ_ERROR, "id", NULL, NULL); free(js_p); } static void test_carbons_discover_cb_empty_reply(void ** state) { (void) state; const char * own_jid = "romeo@montague.example/garden"; const char * reply = "" ""; xmlnode * reply_node_p = xmlnode_from_str(reply, -1); JabberStream * js_p = malloc(sizeof (JabberStream)); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, own_jid); expect_function_call(__wrap_purple_debug_error); carbons_discover_cb(js_p, "montague.example", JABBER_IQ_RESULT, "id", reply_node_p, NULL); free(js_p); } /** * Do nothing (and especially not crash) when the xmlnode ** is null. Some plugins do this. */ static void test_carbons_xml_received_cb_nullptr(void ** state) { (void) state; carbons_xml_received_cb(NULL, NULL); } /** * Do not crash when the given xmlnode * is null. */ static void test_carbons_xml_received_cb_null(void ** state) { (void) state; xmlnode * node_p = NULL; carbons_xml_received_cb(NULL, &node_p); } /** * Stop processing when the received stanza is not a 'message'. */ static void test_carbons_xml_received_cb_no_msg(void ** state) { (void) state; char * stanza = "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" ""; xmlnode * iq_node_p = xmlnode_from_str(stanza, -1); carbons_xml_received_cb(NULL, &iq_node_p); xmlnode * body_node_p = xmlnode_get_child(iq_node_p, "body"); assert_string_equal("Neither, fair saint, if either thee dislike.", xmlnode_get_data(body_node_p)); } /** * 'Reject' carbons messages sent by someone other than the own, bare JID. * Removes the inner carbons node since it's a malicious message. */ static void test_carbons_xml_received_cb_invalid_sender_received(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "" "What man art thou that, thus bescreen'd in night, so stumblest on my counsel?" "0e3141cd80894871a68e6fe6b1ec56fa" "" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); expect_function_calls(__wrap_purple_debug_warning, 2); carbons_xml_received_cb(NULL, &received_carbons_node_p); assert_non_null(received_carbons_node_p); assert_null(xmlnode_get_child(received_carbons_node_p, "received")); } /** * Same as above, but for a carbon copy of a sent message. */ static void test_carbons_xml_received_cb_invalid_sender_sent(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" "" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); expect_function_calls(__wrap_purple_debug_warning, 2); carbons_xml_received_cb(NULL, &received_carbons_node_p); assert_non_null(received_carbons_node_p); assert_null(xmlnode_get_child(received_carbons_node_p, "sent")); } /** * Default case for a received carbon copy of a received message: * Strip outer message and give libpurple the inner one. */ static void test_carbons_xml_received_cb_received_success(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "" "What man art thou that, thus bescreen'd in night, so stumblest on my counsel?" "0e3141cd80894871a68e6fe6b1ec56fa" "" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); carbons_xml_received_cb(NULL, &received_carbons_node_p); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "juliet@capulet.example/balcony"); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/garden"); assert_ptr_not_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); } /** * Stop processing on malformed carbon-copy of received message: no 'forwarded' node. */ static void test_carbons_xml_received_cb_received_no_forwarded(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "What man art thou that, thus bescreen'd in night, so stumblest on my counsel?" "0e3141cd80894871a68e6fe6b1ec56fa" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); expect_function_call(__wrap_purple_debug_error); carbons_xml_received_cb(NULL, &received_carbons_node_p); // no change since there was no processing assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/home"); assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); } /** * Stop processing on malformed carbon-copy of received message: no 'message' node. */ static void test_carbons_xml_received_cb_received_no_message(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); expect_function_call(__wrap_purple_debug_error); carbons_xml_received_cb(NULL, &received_carbons_node_p); // no change since there was no processing assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/home"); assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); } /** * Default case for a received carbon copy of a sent message: * Strip the outer message and give libpurple the inner one, * plus inject another '' node for detection by second, later callback. */ static void test_carbons_xml_received_cb_sent_success(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" "" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); carbons_xml_received_cb(NULL, &received_carbons_node_p); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example/home"); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "juliet@capulet.example/balcony"); assert_ptr_not_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); assert_ptr_not_equal(xmlnode_get_child_with_namespace(received_carbons_node_p, "sent", CARBONS_XMLNS), NULL); } /** * Stop processing on malformed carbon-copy of sent message: no 'forwaded' node. */ static void test_carbons_xml_received_cb_sent_no_forwarded(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); expect_function_call(__wrap_purple_debug_error); carbons_xml_received_cb(NULL, &received_carbons_node_p); // no change since there was no processing assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/garden"); assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); } /** * Stop processing on malformed carbon-copy of sent message: no 'message' node. */ static void test_carbons_xml_received_cb_sent_no_message(void ** state) { (void) state; const char * received_carbon_copy = "" "" "" "" ""; xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); will_return(__wrap_purple_account_get_username, "romeo@montague.example"); expect_function_call(__wrap_purple_debug_error); carbons_xml_received_cb(NULL, &received_carbons_node_p); // no change since there was no processing assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/garden"); assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); } static void test_carbons_xml_stripped_cb_nullptr(void ** state) { (void) state; carbons_xml_stripped_cb(NULL, NULL); } static void test_carbons_xml_stripped_cb_null(void ** state) { (void) state; xmlnode * node_p = NULL; carbons_xml_stripped_cb(NULL, &node_p); } /** * If the stanza contains an empty 'sent' node injected by the earlier callback, write the body to the conversation. */ static void test_carbons_xml_stripped_cb_success(void ** state) { (void) state; const char * stripped_carbon_copy = "" "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" ""; xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); will_return(__wrap_purple_connection_get_account, NULL); PurpleConversation * pc_p = NULL; will_return(__wrap_purple_find_conversation_with_account, &pc_p); expect_value(__wrap_purple_conversation_write, conv_p, &pc_p); expect_string(__wrap_purple_conversation_write, who, "romeo@montague.example/home"); expect_string(__wrap_purple_conversation_write, message, "Neither, fair saint, if either thee dislike."); expect_value(__wrap_purple_conversation_write, flags, PURPLE_MESSAGE_SEND); carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); assert_non_null(stripped_carbons_node_p); assert_null(xmlnode_get_child(stripped_carbons_node_p, "sent")); assert_null(xmlnode_get_child(stripped_carbons_node_p, "body")); } /** * Like above, but also create the conversation window if it does not exist yet. */ static void test_carbons_xml_stripped_cb_success_new_conv(void ** state) { (void) state; const char * stripped_carbon_copy = "" "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" ""; xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); char * acc_mock = "fake purple account"; will_return(__wrap_purple_connection_get_account, &acc_mock); will_return(__wrap_purple_find_conversation_with_account, NULL); expect_value(__wrap_purple_conversation_new, type, PURPLE_CONV_TYPE_IM); expect_value(__wrap_purple_conversation_new, account, &acc_mock); expect_string(__wrap_purple_conversation_new, name, "juliet@capulet.example"); PurpleConversation * pc_p = NULL; will_return(__wrap_purple_conversation_new, &pc_p); expect_value(__wrap_purple_conversation_write, conv_p, &pc_p); expect_string(__wrap_purple_conversation_write, who, "romeo@montague.example/home"); expect_string(__wrap_purple_conversation_write, message, "Neither, fair saint, if either thee dislike."); expect_value(__wrap_purple_conversation_write, flags, PURPLE_MESSAGE_SEND); carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); assert_non_null(stripped_carbons_node_p); assert_null(xmlnode_get_child(stripped_carbons_node_p, "sent")); assert_null(xmlnode_get_child(stripped_carbons_node_p, "body")); } /** * Do nothing if the stanza is not a 'message'. */ static void test_carbons_xml_stripped_cb_not_a_message(void ** state) { (void) state; const char * stripped_carbon_copy = "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" ""; xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); assert_string_equal(xmlnode_to_str(stripped_carbons_node_p, NULL), stripped_carbon_copy); } /** * Do nothing if the stanza does not contain an empty 'sent' node. */ static void test_carbons_xml_stripped_cb_do_nothing(void ** state) { (void) state; const char * stripped_carbon_copy = "" "Neither, fair saint, if either thee dislike." "0e3141cd80894871a68e6fe6b1ec56fa" ""; xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); assert_string_equal(xmlnode_to_str(stripped_carbons_node_p, NULL), stripped_carbon_copy); } /** * Add carbons to client capabilities, register the init callback for accounts signing on, * and also the two message handling callbacks on incoming XML. */ static void test_carbons_plugin_load_app_start(void ** state) { (void) state; void * plugin_mock = "plugin mock"; void * accounts_handle_mock = "accounts handle mock"; will_return(__wrap_purple_accounts_get_handle, accounts_handle_mock); expect_value(__wrap_purple_signal_connect, instance, accounts_handle_mock); expect_string(__wrap_purple_signal_connect, signal, "account-signed-on"); expect_value(__wrap_purple_signal_connect, handle, plugin_mock); expect_value(__wrap_purple_signal_connect, func, carbons_account_connect_cb); void * jabber_handle_mock = "jabber handle mock"; expect_string_count(__wrap_purple_plugins_find_with_id, id, "prpl-jabber", 2); will_return_count(__wrap_purple_plugins_find_with_id, jabber_handle_mock, 2); expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_received_cb); expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_LOWEST + 100); expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_stripped_cb); expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_HIGHEST - 50); will_return(__wrap_purple_accounts_get_all_active, NULL); expect_string(__wrap_jabber_add_feature, namespace, CARBONS_XMLNS); assert_true(carbons_plugin_load(plugin_mock)); } /** * If the plugin is loaded while the application is already running, the functions which are usually called on * account connect have to be called manually. */ static void test_carbons_plugin_load_while_connected(void ** state) { (void) state; void * plugin_mock = "plugin mock"; void * accounts_handle_mock = "accounts handle mock"; will_return(__wrap_purple_accounts_get_handle, accounts_handle_mock); expect_value(__wrap_purple_signal_connect, instance, accounts_handle_mock); expect_string(__wrap_purple_signal_connect, signal, "account-signed-on"); expect_value(__wrap_purple_signal_connect, handle, plugin_mock); expect_value(__wrap_purple_signal_connect, func, carbons_account_connect_cb); void * jabber_handle_mock = "jabber handle mock"; expect_string_count(__wrap_purple_plugins_find_with_id, id, "prpl-jabber", 2); will_return_count(__wrap_purple_plugins_find_with_id, jabber_handle_mock, 2); expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_received_cb); expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_LOWEST + 100); expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_stripped_cb); expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_HIGHEST - 50); PurpleAccount * account_p = malloc(sizeof(PurpleAccount)); will_return(__wrap_purple_accounts_get_all_active, g_list_prepend(NULL, account_p)); will_return(__wrap_purple_account_is_connected, TRUE); expect_value(__wrap_purple_account_get_protocol_id, acc_p, account_p); will_return(__wrap_purple_account_get_protocol_id, "does not matter, just checking if function is called"); // unfortunately, there is currently no way to check that jabber_add_feature was NOT called assert_true(carbons_plugin_load(plugin_mock)); free(account_p); } /** * Send a discovery request on account connect, but only if the connecting account is of type XMPP- */ static void test_carbons_account_connect_cb(void ** state) { (void) state; const char * test_domain = "test.org"; const char * test_jid = "me-testing@test.org/resource"; will_return(__wrap_purple_account_get_protocol_id, "prpl-jabber"); expect_any(__wrap_purple_account_get_protocol_id, acc_p); will_return(__wrap_purple_account_get_connection, NULL); JabberStream * js_p = malloc(sizeof (JabberStream)); js_p->next_id = 1; js_p->user = jabber_id_new(test_jid); will_return(__wrap_purple_connection_get_protocol_data, js_p); will_return(__wrap_purple_account_get_username, test_jid); expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_GET); expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_discover_cb); expect_string(__wrap_jabber_iq_send, to, test_domain); expect_not_value(__wrap_jabber_iq_send, query_node_p, NULL); // not set here expect_value(__wrap_jabber_iq_send, enable_node_p, NULL); carbons_account_connect_cb(NULL); free(js_p); } /** * Notify user of an error if enabling carbons fails. */ static void test_carbons_enable_cb_error(void ** state) { (void) state; will_return(__wrap_purple_connection_get_account, "does not matter"); will_return(__wrap_purple_account_get_username, "does not matter"); expect_function_call(__wrap_purple_debug_error); JabberStream * js_p = malloc(sizeof (JabberStream)); carbons_enable_cb(js_p, "", JABBER_IQ_ERROR, "", NULL, NULL); free(js_p); } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_carbons_discover_cb_success), cmocka_unit_test(test_carbons_discover_cb_real_world_reply), cmocka_unit_test(test_carbons_discover_cb_first_child), cmocka_unit_test(test_carbons_discover_cb_last_child), cmocka_unit_test(test_carbons_discover_cb_no_carbons), cmocka_unit_test(test_carbons_discover_cb_error), cmocka_unit_test(test_carbons_discover_cb_empty_reply), cmocka_unit_test(test_carbons_xml_received_cb_nullptr), cmocka_unit_test(test_carbons_xml_received_cb_null), cmocka_unit_test(test_carbons_xml_received_cb_no_msg), cmocka_unit_test(test_carbons_xml_received_cb_invalid_sender_received), cmocka_unit_test(test_carbons_xml_received_cb_invalid_sender_sent), cmocka_unit_test(test_carbons_xml_received_cb_received_success), cmocka_unit_test(test_carbons_xml_received_cb_received_no_forwarded), cmocka_unit_test(test_carbons_xml_received_cb_received_no_message), cmocka_unit_test(test_carbons_xml_received_cb_sent_success), cmocka_unit_test(test_carbons_xml_received_cb_sent_no_forwarded), cmocka_unit_test(test_carbons_xml_received_cb_sent_no_message), cmocka_unit_test(test_carbons_xml_stripped_cb_nullptr), cmocka_unit_test(test_carbons_xml_stripped_cb_null), cmocka_unit_test(test_carbons_xml_stripped_cb_success), cmocka_unit_test(test_carbons_xml_stripped_cb_success_new_conv), cmocka_unit_test(test_carbons_xml_stripped_cb_not_a_message), cmocka_unit_test(test_carbons_xml_stripped_cb_do_nothing), cmocka_unit_test(test_carbons_plugin_load_app_start), cmocka_unit_test(test_carbons_plugin_load_while_connected), cmocka_unit_test(test_carbons_account_connect_cb), cmocka_unit_test(test_carbons_enable_cb_error) }; return cmocka_run_group_tests(tests, NULL, NULL); }