├── .appveyor.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── Makefile.mingw ├── README.md ├── headers └── jabber │ ├── adhoccommands.h │ ├── auth.h │ ├── auth_digest_md5.h │ ├── auth_scram.h │ ├── bosh.h │ ├── buddy.h │ ├── caps.h │ ├── chat.h │ ├── data.h │ ├── disco.h │ ├── facebook_roster.h │ ├── ibb.h │ ├── iq.h │ ├── jabber.h │ ├── jutil.h │ ├── message.h │ ├── namespaces.h │ ├── oob.h │ ├── parser.h │ ├── pep.h │ ├── ping.h │ ├── presence.h │ ├── roster.h │ ├── si.h │ ├── useravatar.h │ ├── usermood.h │ ├── usernick.h │ ├── usertune.h │ └── xdata.h ├── src ├── carbons.c ├── carbons.h └── carbons_internal.h └── test ├── mocks.c └── test_carbons.c /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.2.3-dev-{build} 2 | 3 | image: Ubuntu1804 4 | 5 | install: 6 | - sh: sudo apt-get update 7 | - sh: sudo apt-get install -y libpurple-dev libglib2.0-dev libxml2-dev libcmocka-dev mingw-w64 unzip --no-install-recommends 8 | 9 | build_script: 10 | - sh: make 11 | - sh: make win 12 | 13 | test_script: 14 | - sh: CMOCKA_MESSAGE_OUTPUT=XML CMOCKA_XML_FILE=build/cmocka_results.xml make test 15 | 16 | after_test: 17 | - sh: curl -v -F "file=@$APPVEYOR_BUILD_FOLDER/build/cmocka_results.xml" "https://ci.appveyor.com/api/testresults/junit/$APPVEYOR_JOB_ID" 18 | - sh: bash <(curl -s https://codecov.io/bash) -g test/ -B $APPVEYOR_REPO_BRANCH -b $APPVEYOR_BUILD_VERSION 19 | 20 | cache: 21 | - win32_dev 22 | 23 | artifacts: 24 | - path: build/carbons.so 25 | name: carbons-$APPVEYOR_BUILD_VERSION-$APPVEYOR_REPO_COMMIT.so 26 | - path: build/carbons.dll 27 | name: carbons-$APPVEYOR_BUILD_VERSION-$APPVEYOR_REPO_COMMIT.dll 28 | 29 | deploy: 30 | description: 'Release description' 31 | provider: GitHub 32 | auth_token: 33 | secure: cdAyB4V+IR862PUMggKUTfrWBlZa3VUg5tolJzARYajRxWLiYGzw2VQcAPpmHZsL 34 | artifact: build/carbons.so,build/carbons.dll 35 | draft: true 36 | on: 37 | APPVEYOR_REPO_TAG: true 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ 3 | win32_dev/ 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [0.2.3] - 2020-12-25 8 | ### Added 9 | - This file. 10 | - LICENSE file to make GitHub happy ([#39](https://github.com/gkdr/carbons/issues/39)). 11 | - The implemented XEP version to the README ([#41](https://github.com/gkdr/carbons/issues/41)). 12 | - 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) :) ) 13 | 14 | ### Fixed 15 | - AppVeyor will now only push tagged builds to GitHub releases. 16 | - Set `rpath` for regular build instead of just for tests ([#38](https://github.com/gkdr/carbons/pull/38)) (thanks, [@wladmis](https://github.com/wladmis)!). 17 | - Stop leaking the retrieved message body ([#42](https://github.com/gkdr/carbons/pull/42)) (thanks, [@henry-nicolas](https://github.com/henry-nicolas)!). 18 | - Preserve `CPPFLAGS` and `LDFLAGS` from env ([#43](https://github.com/gkdr/carbons/pull/43)) (thanks, [@henry-nicolas](https://github.com/henry-nicolas)!). 19 | 20 | ## [0.2.2] and below 21 | Lost to git commit logs and the GitHub releases page. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | PKG_CONFIG ?= pkg-config 3 | 4 | LDIR=./lib 5 | BDIR=./build 6 | SDIR=./src 7 | HDIR=./headers 8 | TDIR=./test 9 | PURPLE_DIR=$(shell $(PKG_CONFIG) --variable=plugindir purple) 10 | 11 | GLIB_CFLAGS ?= $(shell $(PKG_CONFIG) --cflags glib-2.0) 12 | GLIB_LDFLAGS ?= $(shell $(PKG_CONFIG) --libs glib-2.0) 13 | 14 | LIBPURPLE_CFLAGS ?= $(shell $(PKG_CONFIG) --cflags purple) 15 | LIBPURPLE_LDFLAGS ?= $(shell $(PKG_CONFIG) --cflags purple) -L$(PURPLE_DIR) 16 | 17 | PURPLE_PLUGIN_DIR ?= $(shell $(PKG_CONFIG) --variable=plugindir purple) 18 | PURPLE_HOME_PLUGIN_DIR=$(HOME)/.purple/plugins 19 | 20 | XML2_CONFIG ?= xml2-config 21 | XML2_CFLAGS ?= $(shell $(XML2_CONFIG) --cflags) 22 | XML2_LDFLAGS ?= $(shell $(XML2_CONFIG) --libs) 23 | 24 | 25 | HEADERS=-I$(HDIR)/jabber 26 | 27 | PKGCFG_C=$(GLIB_CFLAGS) \ 28 | $(LIBPURPLE_CFLAGS) \ 29 | $(XML2_CFLAGS) 30 | 31 | PKGCFG_L=$(GLIB_LDFLAGS) \ 32 | $(LIBPURPLE_LDFLAGS) \ 33 | $(XML2_LDFLAGS) 34 | 35 | FLAGS+=-std=c11 -Wall -g -Wstrict-overflow -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_DEFAULT_SOURCE $(CPPFLAGS) 36 | CFLAGS+= $(FLAGS) $(PKGCFG_C) $(HEADERS) 37 | CFLAGS_C= $(CFLAGS) -fPIC -shared 38 | CFLAGS_T= $(CFLAGS) -O0 39 | PLUGIN_CPPFLAGS=-DPURPLE_PLUGINS 40 | 41 | ifneq ("$(wildcard /etc/redhat-release)","") 42 | LJABBER?=-lxmpp 43 | else 44 | LJABBER?=-ljabber 45 | endif 46 | 47 | LFLAGS= $(LDFLAGS) -ldl -lm $(PKGCFG_L) $(LJABBER) -Wl,-rpath,$(PURPLE_DIR) 48 | LFLAGS_T= $(LFLAGS) -lpurple -lcmocka \ 49 | -Wl,--wrap=purple_account_is_connected \ 50 | -Wl,--wrap=purple_account_get_connection \ 51 | -Wl,--wrap=purple_account_get_protocol_id \ 52 | -Wl,--wrap=purple_account_get_username \ 53 | -Wl,--wrap=purple_accounts_get_handle \ 54 | -Wl,--wrap=purple_accounts_get_all_active \ 55 | -Wl,--wrap=purple_debug_error \ 56 | -Wl,--wrap=purple_debug_warning \ 57 | -Wl,--wrap=purple_connection_get_account \ 58 | -Wl,--wrap=purple_connection_get_protocol_data \ 59 | -Wl,--wrap=purple_find_conversation_with_account \ 60 | -Wl,--wrap=purple_conversation_new \ 61 | -Wl,--wrap=purple_conversation_write \ 62 | -Wl,--wrap=purple_plugins_find_with_id \ 63 | -Wl,--wrap=purple_signal_connect \ 64 | -Wl,--wrap=purple_signal_connect_priority \ 65 | -Wl,--wrap=jabber_add_feature \ 66 | -Wl,--wrap=jabber_iq_send 67 | 68 | all: $(BDIR)/carbons.so 69 | 70 | $(BDIR): 71 | mkdir -p build 72 | 73 | $(BDIR)/%.o: $(SDIR)/%.c $(BDIR) 74 | $(CC) $(CFLAGS_C) $(PLUGIN_CPPFLAGS) -c $(SDIR)/$*.c -o $@ 75 | 76 | $(BDIR)/carbons.so: $(BDIR)/carbons.o 77 | $(CC) $(CFLAGS_C) $(PLUGIN_CPPFLAGS) $(BDIR)/carbons.o -o $@ $(LFLAGS) 78 | $(BDIR)/carbons.a: $(BDIR)/carbons.o 79 | $(AR) rcs $@ $^ 80 | 81 | $(BDIR)/carbons.dll: $(BDIR)/carbons.o 82 | $(CC) $(CFLAGS_C) $(PLUGIN_CPPFLAGS) $(BDIR)/carbons.o -o $@ $(LFLAGS) 83 | 84 | WIN_CC ?= i686-w64-mingw32-gcc-win32 85 | WIN32_DEV_DIR ?= win32_dev 86 | GLIB_DIR ?= glib-2.28.8 87 | GLIB_PATH = ./$(WIN32_DEV_DIR)/$(GLIB_DIR) 88 | WIN_PIDGIN_PATH = ./$(WIN32_DEV_DIR)/pidgin-2.13.0-win32bin 89 | LIBXML2_DIR ?= libxml2-2.9.2_daa1 90 | LIBXML2_PATH = ./$(WIN32_DEV_DIR)/$(LIBXML2_DIR) 91 | WIN_HEADERS ?= -I$(GLIB_PATH)/include/glib-2.0 \ 92 | -I$(GLIB_PATH)/lib/glib-2.0/include \ 93 | -I/usr/include/libpurple \ 94 | -I./headers/jabber \ 95 | -I$(LIBXML2_PATH)/include/libxml2 96 | WIN_CFLAGS += $(FLAGS) $(WIN_HEADERS) $(PLUGIN_CPPFLAGS) -fPIC -shared 97 | 98 | WIN_LFLAGS = -L$(GLIB_PATH)/lib -lglib-2.0 -L$(WIN_PIDGIN_PATH) -lpurple -ljabber -L$(LIBXML2_PATH)/lib -lxml2 -static-libgcc 99 | 100 | windeps: 101 | mkdir -p $(WIN32_DEV_DIR) 102 | 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 103 | unzip -n $(WIN32_DEV_DIR)/glib-dev_2.28.8-1_win32.zip -d $(GLIB_PATH) 104 | -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 105 | unzip -n $(WIN32_DEV_DIR)/pidgin-2.13.0-win32-bin.zip -d $(WIN32_DEV_DIR) 106 | wget -nc -P $(WIN32_DEV_DIR) https://developer.pidgin.im/static/win32/libxml2-2.9.2_daa1.tar.gz 107 | -tar xvzkf $(WIN32_DEV_DIR)/libxml2-2.9.2_daa1.tar.gz --directory $(WIN32_DEV_DIR) 108 | 109 | win: $(SDIR)/carbons.c $(BDIR) windeps 110 | $(WIN_CC) $(WIN_CFLAGS) -c ./src/carbons.c -o $(BDIR)/carbons_win.o 111 | $(WIN_CC) $(WIN_CFLAGS) $(BDIR)/carbons_win.o -o $(BDIR)/carbons.dll $(WIN_LFLAGS) 112 | 113 | install: $(BDIR)/carbons.so 114 | install -Dm0644 $(BDIR)/carbons.so $(DESTDIR)$(PURPLE_PLUGIN_DIR)/carbons.so 115 | 116 | install-home: $(BDIR)/carbons.so 117 | install -Dm0644 $(BDIR)/carbons.so $(PURPLE_HOME_PLUGIN_DIR)/carbons.so 118 | 119 | .PHONY: test 120 | test: $(TDIR)/test_carbons.c $(BDIR) 121 | $(CC) $(CFLAGS_T) -c $< -o $(BDIR)/$@.o 122 | $(CC) $(CFLAGS_T) --coverage -c $(SDIR)/carbons.c -o $(BDIR)/carbons_coverage.o 123 | $(CC) $(CFLAGS_T) --coverage $(PURPLE_DIR)/libjabber.so.0 $(BDIR)/$@.o $(BDIR)/carbons_coverage.o -o $(BDIR)/$@ $(LFLAGS_T) 124 | -$(BDIR)/$@ 2>&1 | grep -Ev ".*CRITICAL.*" | tr -s '\n' # filter annoying and irrelevant glib output 125 | 126 | .PHONY: coverage 127 | coverage: test 128 | gcovr -r . --html --html-details -o build/coverage.html 129 | gcovr -r . -s 130 | 131 | .PHONY: clean 132 | clean: 133 | rm -rf $(BDIR) 134 | 135 | .PHONY: clean-all 136 | clean-all: clean 137 | rm -rf $(WIN32_DEV_DIR) 138 | -------------------------------------------------------------------------------- /Makefile.mingw: -------------------------------------------------------------------------------- 1 | PURPLE_PLUGIN_DIR = c:/Program\ Files\ \(x86\)/Pidgin/plugins 2 | PIDGIN_DIR ?= ../pidgin-2.11.0 3 | LIBPURPLE_DIR ?= $(PIDGIN_DIR)/libpurple 4 | WIN32_DEV_TOP ?= $(PIDGIN_DIR)/../win32-dev 5 | LIBXML2_TOP ?= $(WIN32_DEV_TOP)/libxml2-2.9.0 6 | 7 | CC := $(WIN32_DEV_TOP)/mingw-4.7.2/bin/gcc 8 | 9 | LDIR = ./lib 10 | BDIR = ./build 11 | SDIR = ./src 12 | HDIR = ./headers 13 | 14 | HEADERS = -I$(HDIR)/jabber 15 | 16 | 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 17 | 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 18 | 19 | CFLAGS = -std=c11 -Wall -g -Wstrict-overflow -D_XOPEN_SOURCE=700 -D_BSD_SOURCE $(PKGCFG_C) $(HEADERS) 20 | LFLAGS = $(PKGCFG_L) -ljabber -static-libgcc 21 | 22 | 23 | all: $(BDIR)/carbons.dll 24 | 25 | $(BDIR): 26 | mkdir -p build 27 | 28 | $(BDIR)/carbons.dll: $(SDIR)/carbons.c $(BDIR) 29 | $(CC) $(CFLAGS) -c $(SDIR)/carbons.c -o $(BDIR)/carbons.o 30 | $(CC) -shared $(CFLAGS) $(BDIR)/carbons.o -o $@ $(LFLAGS) 31 | 32 | install: $(BDIR)/carbons.dll 33 | mkdir -p $(PURPLE_PLUGIN_DIR) 34 | install -p $(BDIR)/carbons.dll $(PURPLE_PLUGIN_DIR)/carbons.dll 35 | 36 | .PHONY: clean 37 | clean: 38 | rm -rf $(BDIR) 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # carbons 0.2.3 2 | [![Build status](https://ci.appveyor.com/api/projects/status/0t32ouomatf2teld/branch/dev?svg=true)](https://ci.appveyor.com/project/gkdr/carbons/branch/dev) 3 | [![codecov](https://codecov.io/gh/gkdr/carbons/branch/dev/graph/badge.svg)](https://codecov.io/gh/gkdr/carbons) 4 | [![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) 5 | 6 | Experimental [XEP-0280: Message Carbons](https://xmpp.org/extensions/xep-0280.html) (v0.13.2) plugin for libpurple (Pidgin, Finch, etc.). 7 | 8 | It enables you to have a consistent view of both sent and received messages between all devices which are online at the same time. 9 | 10 | ## Installation 11 | You can find compiled versions of this plugin for both Linux and Windows on [the GitHub releases page](https://github.com/gkdr/carbons/releases). 12 | 13 | 14 | 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). 15 | 16 | ## Usage 17 | 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. 18 | 19 | If something is not working right, consult the debug window. 20 | 21 | 22 | ## Building it yourself 23 | 24 | ### Linux 25 | 1. Install the dependencies (`libpurple-dev`, `libglib2.0-dev`, `libxml2-dev`) 26 | 2. `git clone https://github.com/gkdr/carbons.git` 27 | 3. `cd carbons` 28 | 4. `make` 29 | 5. A final `make install` should copy the plugin into your libpurple plugin dir, or `make install-home` to copy it into `~/.purple/plugins`. 30 | 31 | ### MacOS 32 | 33 | Install dependencies using Homebrew. 34 | 35 | ``` 36 | brew install glib libxml2 37 | ``` 38 | 39 | Get a copy of the libpurple soure (from Pidgin), and prepare it so we can use it 40 | during the build. 41 | 42 | ``` 43 | hg clone https://bitbucket.org/pidgin/main pidgin 44 | cd pidgin 45 | hg checkout v2.10.12 46 | ./configure $(./configure --help | grep -i -- --disable | awk '{ print $1 }') 47 | ``` 48 | 49 | ``` 50 | make LIBPURPLE_CFLAGS=-I${PWD}/pidgin/libpurple LIBPURPLE_LDFLAGS=/Applications/Adium.app/Contents/Frameworks/libpurple.framework/libpurple LJABBER= 51 | ``` 52 | 53 | ### Windows 54 | You can make use of the `Makefile.mingw` by EionRobb. 55 | For this, you have to set up a build environment as described in https://developer.pidgin.im/wiki/BuildingWinPidgin. 56 | 57 | ## Caveats 58 | Note that this only synchronizes messages of devices that are online at the same time - for history synchronization, MAM is needed. 59 | There is currently no libpurple plugin for this. 60 | -------------------------------------------------------------------------------- /headers/jabber/adhoccommands.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_ADHOCCOMMANDS_H_ 25 | #define PURPLE_JABBER_ADHOCCOMMANDS_H_ 26 | 27 | #include "jabber.h" 28 | 29 | /* Implementation of XEP-0050 */ 30 | 31 | void jabber_adhoc_disco_result_cb(JabberStream *js, const char *from, 32 | JabberIqType type, const char *id, 33 | xmlnode *packet, gpointer data); 34 | 35 | void jabber_adhoc_execute(JabberStream *js, JabberAdHocCommands *cmd); 36 | 37 | void jabber_adhoc_execute_action(PurpleBlistNode *node, gpointer data); 38 | 39 | void jabber_adhoc_got_list(JabberStream *js, const char *from, xmlnode *query); 40 | 41 | void jabber_adhoc_server_get_list(JabberStream *js); 42 | 43 | void jabber_adhoc_init_server_commands(JabberStream *js, GList **m); 44 | 45 | #endif /* PURPLE_JABBER_ADHOCCOMMANDS_H_ */ 46 | -------------------------------------------------------------------------------- /headers/jabber/auth.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file auth.h Authentication routines 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_AUTH_H_ 25 | #define PURPLE_JABBER_AUTH_H_ 26 | 27 | typedef struct _JabberSaslMech JabberSaslMech; 28 | 29 | #include "jabber.h" 30 | #include "xmlnode.h" 31 | 32 | typedef enum { 33 | JABBER_SASL_STATE_FAIL = -1, /* Abort, Retry, Fail? */ 34 | JABBER_SASL_STATE_OK = 0, /* Hooray! */ 35 | JABBER_SASL_STATE_CONTINUE = 1 /* More authentication required */ 36 | } JabberSaslState; 37 | 38 | struct _JabberSaslMech { 39 | gint8 priority; /* Higher priority will be tried before lower priority */ 40 | const gchar *name; 41 | JabberSaslState (*start)(JabberStream *js, xmlnode *mechanisms, xmlnode **reply, char **msg); 42 | JabberSaslState (*handle_challenge)(JabberStream *js, xmlnode *packet, xmlnode **reply, char **msg); 43 | JabberSaslState (*handle_success)(JabberStream *js, xmlnode *packet, char **msg); 44 | JabberSaslState (*handle_failure)(JabberStream *js, xmlnode *packet, xmlnode **reply, char **msg); 45 | void (*dispose)(JabberStream *js); 46 | }; 47 | 48 | void jabber_auth_start(JabberStream *js, xmlnode *packet); 49 | void jabber_auth_start_old(JabberStream *js); 50 | void jabber_auth_handle_challenge(JabberStream *js, xmlnode *packet); 51 | void jabber_auth_handle_success(JabberStream *js, xmlnode *packet); 52 | void jabber_auth_handle_failure(JabberStream *js, xmlnode *packet); 53 | 54 | JabberSaslMech *jabber_auth_get_plain_mech(void); 55 | JabberSaslMech *jabber_auth_get_digest_md5_mech(void); 56 | JabberSaslMech **jabber_auth_get_scram_mechs(gint *count); 57 | #ifdef HAVE_CYRUS_SASL 58 | JabberSaslMech *jabber_auth_get_cyrus_mech(void); 59 | #endif 60 | 61 | void jabber_auth_add_mech(JabberSaslMech *); 62 | void jabber_auth_remove_mech(JabberSaslMech *); 63 | 64 | void jabber_auth_init(void); 65 | void jabber_auth_uninit(void); 66 | 67 | #endif /* PURPLE_JABBER_AUTH_H_ */ 68 | -------------------------------------------------------------------------------- /headers/jabber/auth_digest_md5.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file auth_digest_md5.h Implementation of SASL DIGEST-MD5 authentication 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_AUTH_DIGEST_MD5_H_ 25 | #define PURPLE_JABBER_AUTH_DIGEST_MD5_H_ 26 | 27 | #include "internal.h" 28 | 29 | /* 30 | * Every function in this file is ONLY exposed for tests. 31 | * DO NOT USE ANYTHING HERE OR YOU WILL BE SENT TO THE PIT OF DESPAIR. 32 | */ 33 | 34 | /* 35 | * Parse a DIGEST-MD5 challenge. 36 | */ 37 | GHashTable *jabber_auth_digest_md5_parse(const char *challenge); 38 | 39 | #endif /* PURPLE_JABBER_AUTH_DIGEST_MD5_H_ */ 40 | -------------------------------------------------------------------------------- /headers/jabber/auth_scram.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file auth_scram.h Implementation of SASL-SCRAM authentication 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_AUTH_SCRAM_H_ 25 | #define PURPLE_JABBER_AUTH_SCRAM_H_ 26 | 27 | /* 28 | * Every function in this file is ONLY exposed for tests. 29 | * DO NOT USE ANYTHING HERE OR YOU WILL BE SENT TO THE PIT OF DESPAIR. 30 | */ 31 | 32 | /* Per-connection state stored between messages. 33 | * This is stored in js->auth_data_mech. 34 | */ 35 | typedef struct { 36 | const char *mech_substr; 37 | const char *name; 38 | guint size; 39 | } JabberScramHash; 40 | 41 | typedef struct { 42 | const JabberScramHash *hash; 43 | char *cnonce; 44 | GString *auth_message; 45 | 46 | GString *client_proof; 47 | GString *server_signature; 48 | 49 | gchar *password; 50 | gboolean channel_binding; 51 | int step; 52 | } JabberScramData; 53 | 54 | #include "auth.h" 55 | 56 | /** 57 | * Implements the Hi() function as described in the SASL-SCRAM I-D. 58 | * 59 | * @param hash The struct corresponding to the hash function to be used. 60 | * @param str The string to perform the PBKDF2 operation on. 61 | * @param salt The salt. 62 | * @param iterations The number of iterations to perform. 63 | * 64 | * @returns A newly allocated string containing the result. The string is 65 | * NOT null-terminated and its length is the length of the binary 66 | * output of the hash function in-use. 67 | */ 68 | guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str, 69 | GString *salt, guint iterations); 70 | 71 | /** 72 | * Calculates the proofs as described in Section 3 of the SASL-SCRAM I-D. 73 | * 74 | * @param data A JabberScramData structure. hash and auth_message must be 75 | * set. client_proof and server_signature will be set as a result 76 | * of this function. 77 | * @param salt The salt (as specified by the server) 78 | * @param iterations The number of iterations to perform. 79 | * 80 | * @returns TRUE if the proofs were successfully calculated. FALSE otherwise. 81 | */ 82 | gboolean jabber_scram_calc_proofs(JabberScramData *data, GString *salt, 83 | guint iterations); 84 | 85 | /** 86 | * Feed the algorithm with the data from the server. 87 | */ 88 | gboolean jabber_scram_feed_parser(JabberScramData *data, gchar *in, gchar **out); 89 | 90 | /** 91 | * Clean up and destroy the data struct 92 | */ 93 | void jabber_scram_data_destroy(JabberScramData *data); 94 | 95 | #endif /* PURPLE_JABBER_AUTH_SCRAM_H_ */ 96 | -------------------------------------------------------------------------------- /headers/jabber/bosh.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bosh.h Bidirectional-streams over Synchronous HTTP (BOSH) (XEP-0124 and XEP-0206) 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_BOSH_H_ 25 | #define PURPLE_JABBER_BOSH_H_ 26 | 27 | typedef struct _PurpleBOSHConnection PurpleBOSHConnection; 28 | 29 | #include "jabber.h" 30 | 31 | void jabber_bosh_init(void); 32 | void jabber_bosh_uninit(void); 33 | 34 | PurpleBOSHConnection* jabber_bosh_connection_init(JabberStream *js, const char *url); 35 | void jabber_bosh_connection_destroy(PurpleBOSHConnection *conn); 36 | 37 | gboolean jabber_bosh_connection_is_ssl(PurpleBOSHConnection *conn); 38 | void jabber_bosh_connection_send_keepalive(PurpleBOSHConnection *conn); 39 | 40 | void jabber_bosh_connection_connect(PurpleBOSHConnection *conn); 41 | void jabber_bosh_connection_close(PurpleBOSHConnection *conn); 42 | void jabber_bosh_connection_send_raw(PurpleBOSHConnection *conn, const char *data); 43 | #endif /* PURPLE_JABBER_BOSH_H_ */ 44 | -------------------------------------------------------------------------------- /headers/jabber/buddy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file buddy.h Buddy handlers 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_BUDDY_H_ 25 | #define PURPLE_JABBER_BUDDY_H_ 26 | 27 | typedef struct _JabberBuddy JabberBuddy; 28 | 29 | #include "jabber.h" 30 | #include "caps.h" 31 | #include "jutil.h" 32 | 33 | struct _JabberBuddy { 34 | /** 35 | * A sorted list of resources in priority descending order. 36 | * This means that the first resource in the list is the 37 | * "most available" (see resource_compare_cb in buddy.c for 38 | * details). Don't play with this yourself, let 39 | * jabber_buddy_track_resource and jabber_buddy_remove_resource do it. 40 | */ 41 | GList *resources; 42 | char *error_msg; 43 | enum { 44 | JABBER_INVISIBLE_NONE = 0, 45 | JABBER_INVISIBLE_SERVER = 1 << 1, 46 | JABBER_INVIS_BUDDY = 1 << 2 47 | } invisible; 48 | enum { 49 | JABBER_SUB_NONE = 0, 50 | JABBER_SUB_PENDING = 1 << 1, 51 | JABBER_SUB_TO = 1 << 2, 52 | JABBER_SUB_FROM = 1 << 3, 53 | JABBER_SUB_BOTH = (JABBER_SUB_TO | JABBER_SUB_FROM), 54 | JABBER_SUB_REMOVE = 1 << 4 55 | } subscription; 56 | }; 57 | 58 | typedef struct _JabberAdHocCommands { 59 | char *jid; 60 | char *node; 61 | char *name; 62 | } JabberAdHocCommands; 63 | 64 | typedef struct _JabberBuddyResource { 65 | JabberBuddy *jb; 66 | char *name; 67 | int priority; 68 | JabberBuddyState state; 69 | char *status; 70 | time_t idle; 71 | JabberCapabilities capabilities; 72 | char *thread_id; 73 | enum { 74 | JABBER_CHAT_STATES_UNKNOWN, 75 | JABBER_CHAT_STATES_UNSUPPORTED, 76 | JABBER_CHAT_STATES_SUPPORTED 77 | } chat_states; 78 | struct { 79 | char *version; 80 | char *name; 81 | char *os; 82 | } client; 83 | /* tz_off == PURPLE_NO_TZ_OFF when unset */ 84 | long tz_off; 85 | struct { 86 | JabberCapsClientInfo *info; 87 | GList *exts; 88 | } caps; 89 | GList *commands; 90 | gboolean commands_fetched; 91 | } JabberBuddyResource; 92 | 93 | void jabber_buddy_free(JabberBuddy *jb); 94 | JabberBuddy *jabber_buddy_find(JabberStream *js, const char *name, 95 | gboolean create); 96 | JabberBuddyResource *jabber_buddy_find_resource(JabberBuddy *jb, 97 | const char *resource); 98 | JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource, 99 | int priority, JabberBuddyState state, const char *status); 100 | void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource); 101 | void jabber_buddy_get_info(PurpleConnection *gc, const char *who); 102 | 103 | GList *jabber_blist_node_menu(PurpleBlistNode *node); 104 | 105 | void jabber_set_info(PurpleConnection *gc, const char *info); 106 | void jabber_setup_set_info(PurplePluginAction *action); 107 | void jabber_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img); 108 | 109 | void jabber_user_search(JabberStream *js, const char *directory); 110 | void jabber_user_search_begin(PurplePluginAction *); 111 | 112 | void jabber_buddy_remove_all_pending_buddy_info_requests(JabberStream *js); 113 | 114 | void jabber_vcard_fetch_mine(JabberStream *js); 115 | 116 | gboolean jabber_resource_know_capabilities(const JabberBuddyResource *jbr); 117 | gboolean jabber_resource_has_capability(const JabberBuddyResource *jbr, 118 | const gchar *cap); 119 | gboolean jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap); 120 | 121 | const gchar * 122 | jabber_resource_get_identity_category_type(const JabberBuddyResource *jbr, 123 | const gchar *category); 124 | 125 | #endif /* PURPLE_JABBER_BUDDY_H_ */ 126 | -------------------------------------------------------------------------------- /headers/jabber/caps.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_CAPS_H_ 25 | #define PURPLE_JABBER_CAPS_H_ 26 | 27 | typedef struct _JabberCapsClientInfo JabberCapsClientInfo; 28 | 29 | #include "jabber.h" 30 | 31 | /* Implementation of XEP-0115 - Entity Capabilities */ 32 | 33 | typedef struct _JabberCapsNodeExts JabberCapsNodeExts; 34 | 35 | typedef struct _JabberCapsTuple { 36 | const char *node; 37 | const char *ver; 38 | const char *hash; 39 | } JabberCapsTuple; 40 | 41 | struct _JabberCapsClientInfo { 42 | GList *identities; /* JabberIdentity */ 43 | GList *features; /* char * */ 44 | GList *forms; /* xmlnode * */ 45 | JabberCapsNodeExts *exts; 46 | 47 | const JabberCapsTuple tuple; 48 | }; 49 | 50 | /* 51 | * This stores a set of exts "known" for a specific node (which indicates 52 | * a specific client -- for reference, Pidgin, Finch, Meebo, et al share one 53 | * node.) In XEP-0115 v1.3, exts are used for features that may or may not be 54 | * present at a given time (PEP things, buzz might be disabled, etc). 55 | * 56 | * This structure is shared among all JabberCapsClientInfo instances matching 57 | * a specific node (if the capstable key->hash == NULL, which indicates that 58 | * the ClientInfo is using v1.3 caps as opposed to v1.5 caps). 59 | * 60 | * It's only exposed so that jabber_resource_has_capability can use it. 61 | * Everyone else, STAY AWAY! 62 | */ 63 | struct _JabberCapsNodeExts { 64 | guint ref; 65 | GHashTable *exts; /* char *ext_name -> GList *features */ 66 | }; 67 | 68 | typedef void (*jabber_caps_get_info_cb)(JabberCapsClientInfo *info, GList *exts, gpointer user_data); 69 | 70 | void jabber_caps_init(void); 71 | void jabber_caps_uninit(void); 72 | 73 | /** 74 | * Check whether all of the exts in a char* array are known to the given info. 75 | */ 76 | gboolean jabber_caps_exts_known(const JabberCapsClientInfo *info, char **exts); 77 | 78 | /** 79 | * Main entity capabilites function to get the capabilities of a contact. 80 | * 81 | * The callback will be called synchronously if we already have the 82 | * capabilities for the specified (node,ver,hash) (and, if exts are specified, 83 | * if we know what each means) 84 | * 85 | * @param exts A g_strsplit'd (NULL-terminated) array of strings. This 86 | * function is responsible for freeing it. 87 | */ 88 | void jabber_caps_get_info(JabberStream *js, const char *who, const char *node, 89 | const char *ver, const char *hash, 90 | char **exts, jabber_caps_get_info_cb cb, 91 | gpointer user_data); 92 | 93 | /** 94 | * Takes a JabberCapsClientInfo pointer and returns the caps hash according to 95 | * XEP-0115 Version 1.5. 96 | * 97 | * @param info A JabberCapsClientInfo pointer. 98 | * @param hash Hash cipher to be used. Either sha-1 or md5. 99 | * @return The base64 encoded SHA-1 hash; must be freed by caller 100 | */ 101 | gchar *jabber_caps_calculate_hash(JabberCapsClientInfo *info, const char *hash); 102 | 103 | /** 104 | * Calculate SHA1 hash for own featureset. 105 | */ 106 | void jabber_caps_calculate_own_hash(JabberStream *js); 107 | 108 | /** Get the current caps hash. 109 | * @ret hash 110 | **/ 111 | const gchar* jabber_caps_get_own_hash(JabberStream *js); 112 | 113 | /** 114 | * Broadcast a new calculated hash using a stanza. 115 | */ 116 | void jabber_caps_broadcast_change(void); 117 | 118 | /** 119 | * Parse the element from an IQ stanza into a JabberCapsClientInfo 120 | * struct. 121 | * 122 | * Exposed for tests 123 | * 124 | * @param query The 'query' element from an IQ reply stanza. 125 | * @returns A JabberCapsClientInfo struct, or NULL on error 126 | */ 127 | JabberCapsClientInfo *jabber_caps_parse_client_info(xmlnode *query); 128 | 129 | #endif /* PURPLE_JABBER_CAPS_H_ */ 130 | -------------------------------------------------------------------------------- /headers/jabber/chat.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file chat.h Chat stuff 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_CHAT_H_ 25 | #define PURPLE_JABBER_CHAT_H_ 26 | 27 | #include "internal.h" 28 | #include "connection.h" 29 | #include "conversation.h" 30 | #include "request.h" 31 | #include "roomlist.h" 32 | 33 | #include "jabber.h" 34 | 35 | typedef struct _JabberChatMember { 36 | char *handle; 37 | char *jid; 38 | } JabberChatMember; 39 | 40 | 41 | typedef struct _JabberChat { 42 | JabberStream *js; 43 | char *room; 44 | char *server; 45 | char *handle; 46 | GHashTable *components; 47 | int id; 48 | PurpleConversation *conv; 49 | gboolean muc; 50 | gboolean xhtml; 51 | PurpleRequestType config_dialog_type; 52 | void *config_dialog_handle; 53 | GHashTable *members; 54 | gboolean left; 55 | time_t joined; 56 | } JabberChat; 57 | 58 | GList *jabber_chat_info(PurpleConnection *gc); 59 | GHashTable *jabber_chat_info_defaults(PurpleConnection *gc, const char *chat_name); 60 | char *jabber_get_chat_name(GHashTable *data); 61 | 62 | /** 63 | * in-prpl function for joining a chat room. Doesn't require sticking goop 64 | * into a hash table. 65 | * 66 | * @param room The room to join. This MUST be normalized already. 67 | * @param server The server the room is on. This MUST be normalized already. 68 | * @param password The password (if required) to join the room. May be NULL. 69 | * @param data The chat hash table. May be NULL (it will be generated 70 | * for current core<>prpl API interface.) 71 | */ 72 | JabberChat *jabber_join_chat(JabberStream *js, const char *room, 73 | const char *server, const char *handle, 74 | const char *password, GHashTable *data); 75 | 76 | void jabber_chat_join(PurpleConnection *gc, GHashTable *data); 77 | JabberChat *jabber_chat_find(JabberStream *js, const char *room, 78 | const char *server); 79 | JabberChat *jabber_chat_find_by_id(JabberStream *js, int id); 80 | JabberChat *jabber_chat_find_by_conv(PurpleConversation *conv); 81 | void jabber_chat_destroy(JabberChat *chat); 82 | void jabber_chat_free(JabberChat *chat); 83 | gboolean jabber_chat_find_buddy(PurpleConversation *conv, const char *name); 84 | void jabber_chat_invite(PurpleConnection *gc, int id, const char *message, 85 | const char *name); 86 | void jabber_chat_leave(PurpleConnection *gc, int id); 87 | char *jabber_chat_buddy_real_name(PurpleConnection *gc, int id, const char *who); 88 | void jabber_chat_request_room_configure(JabberChat *chat); 89 | void jabber_chat_create_instant_room(JabberChat *chat); 90 | void jabber_chat_register(JabberChat *chat); 91 | void jabber_chat_change_topic(JabberChat *chat, const char *topic); 92 | void jabber_chat_set_topic(PurpleConnection *gc, int id, const char *topic); 93 | gboolean jabber_chat_change_nick(JabberChat *chat, const char *nick); 94 | void jabber_chat_part(JabberChat *chat, const char *msg); 95 | void jabber_chat_track_handle(JabberChat *chat, const char *handle, 96 | const char *jid, const char *affiliation, const char *role); 97 | void jabber_chat_remove_handle(JabberChat *chat, const char *handle); 98 | gboolean jabber_chat_ban_user(JabberChat *chat, const char *who, 99 | const char *why); 100 | gboolean jabber_chat_affiliate_user(JabberChat *chat, const char *who, 101 | const char *affiliation); 102 | gboolean jabber_chat_affiliation_list(JabberChat *chat, const char *affiliation); 103 | gboolean jabber_chat_role_user(JabberChat *chat, const char *who, 104 | const char *role, const char *why); 105 | gboolean jabber_chat_role_list(JabberChat *chat, const char *role); 106 | 107 | PurpleRoomlist *jabber_roomlist_get_list(PurpleConnection *gc); 108 | void jabber_roomlist_cancel(PurpleRoomlist *list); 109 | 110 | void jabber_chat_disco_traffic(JabberChat *chat); 111 | 112 | char *jabber_roomlist_room_serialize(PurpleRoomlistRoom *room); 113 | 114 | gboolean jabber_chat_all_participants_have_capability(const JabberChat *chat, 115 | const gchar *cap); 116 | guint jabber_chat_get_num_participants(const JabberChat *chat); 117 | 118 | #endif /* PURPLE_JABBER_CHAT_H_ */ 119 | -------------------------------------------------------------------------------- /headers/jabber/data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Service Discovery 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_DATA_H 25 | #define PURPLE_JABBER_DATA_H 26 | 27 | #include "xmlnode.h" 28 | #include "jabber.h" 29 | 30 | #include 31 | 32 | #define JABBER_DATA_MAX_SIZE 8192 33 | 34 | 35 | typedef struct { 36 | char *cid; 37 | char *type; 38 | gsize size; 39 | gpointer data; 40 | gboolean ephemeral; 41 | } JabberData; 42 | 43 | typedef void (JabberDataRequestCallback)(JabberData *data, gchar *alt, 44 | gpointer userdata); 45 | 46 | 47 | /* creates a JabberData instance from raw data */ 48 | JabberData *jabber_data_create_from_data(gconstpointer data, gsize size, 49 | const char *type, gboolean ephemeral, JabberStream *js); 50 | 51 | /* create a JabberData instance from an XML "data" element (as defined by 52 | XEP 0231 */ 53 | JabberData *jabber_data_create_from_xml(xmlnode *tag); 54 | 55 | /* destroy a JabberData instance, NOT to be used on data that has been 56 | associated, since they get "owned" */ 57 | void jabber_data_destroy(JabberData *data); 58 | 59 | const char *jabber_data_get_cid(const JabberData *data); 60 | const char *jabber_data_get_type(const JabberData *data); 61 | 62 | gsize jabber_data_get_size(const JabberData *data); 63 | gpointer jabber_data_get_data(const JabberData *data); 64 | 65 | /* returns the XML definition for the data element */ 66 | xmlnode *jabber_data_get_xml_definition(const JabberData *data); 67 | 68 | /* returns an XHTML-IM "img" tag given a data instance */ 69 | xmlnode *jabber_data_get_xhtml_im(const JabberData *data, const gchar *alt); 70 | 71 | void jabber_data_request(JabberStream *js, const gchar *cid, const gchar *who, 72 | gchar *alt, gboolean ephemeral, JabberDataRequestCallback cb, 73 | gpointer userdata); 74 | 75 | /* lookup functions */ 76 | const JabberData *jabber_data_find_local_by_alt(const gchar *alt); 77 | const JabberData *jabber_data_find_local_by_cid(const gchar *cid); 78 | const JabberData *jabber_data_find_remote_by_cid(JabberStream *js, 79 | const gchar *who, const gchar *cid); 80 | 81 | /* store data objects */ 82 | void jabber_data_associate_local(JabberData *data, const gchar *alt); 83 | void jabber_data_associate_remote(JabberStream *js, const gchar *who, 84 | JabberData *data); 85 | 86 | /* handles iq requests */ 87 | void jabber_data_parse(JabberStream *js, const char *who, JabberIqType type, 88 | const char *id, xmlnode *data_node); 89 | 90 | void jabber_data_init(void); 91 | void jabber_data_uninit(void); 92 | 93 | #endif /* PURPLE_JABBER_DATA_H */ 94 | -------------------------------------------------------------------------------- /headers/jabber/disco.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file disco.h Jabber Service Discovery 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_DISCO_H_ 25 | #define PURPLE_JABBER_DISCO_H_ 26 | 27 | #include "jabber.h" 28 | 29 | typedef struct _JabberDiscoItem { 30 | const char *jid; /* MUST */ 31 | const char *node; /* SHOULD */ 32 | const char *name; /* MAY */ 33 | } JabberDiscoItem; 34 | 35 | typedef void (JabberDiscoInfoCallback)(JabberStream *js, const char *who, 36 | JabberCapabilities capabilities, gpointer data); 37 | 38 | typedef void (JabberDiscoItemsCallback)(JabberStream *js, const char *jid, 39 | const char *node, GSList *items, gpointer data); 40 | 41 | void jabber_disco_info_parse(JabberStream *js, const char *from, 42 | JabberIqType type, const char *id, xmlnode *in_query); 43 | void jabber_disco_items_parse(JabberStream *js, const char *from, 44 | JabberIqType type, const char *id, xmlnode *query); 45 | 46 | void jabber_disco_items_server(JabberStream *js); 47 | 48 | void jabber_disco_info_do(JabberStream *js, const char *who, 49 | JabberDiscoInfoCallback *callback, gpointer data); 50 | 51 | #endif /* PURPLE_JABBER_DISCO_H_ */ 52 | -------------------------------------------------------------------------------- /headers/jabber/facebook_roster.h: -------------------------------------------------------------------------------- 1 | /** 2 | * purple 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | */ 22 | #ifndef PURPLE_XMPP_FACEBOOK_ROSTER_H_ 23 | #define PURPLE_XMPP_FACEBOOK_ROSTER_H_ 24 | 25 | #include "jabber.h" 26 | 27 | /* removes deleted buddies from the list */ 28 | void 29 | jabber_facebook_roster_cleanup(JabberStream *js, xmlnode *query); 30 | 31 | /* ignores facebook roster quirks */ 32 | gboolean 33 | jabber_facebook_roster_incoming(JabberStream *js, xmlnode *item); 34 | 35 | #endif /* PURPLE_XMPP_FACEBOOK_ROSTER_H_ */ 36 | -------------------------------------------------------------------------------- /headers/jabber/ibb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Service Discovery 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_IBB_H_ 25 | #define PURPLE_JABBER_IBB_H_ 26 | 27 | #include "jabber.h" 28 | #include "iq.h" 29 | 30 | typedef struct _JabberIBBSession JabberIBBSession; 31 | 32 | typedef void 33 | (JabberIBBDataCallback)(JabberIBBSession *, const gpointer data, gsize size); 34 | 35 | typedef void (JabberIBBOpenedCallback)(JabberIBBSession *); 36 | typedef void (JabberIBBClosedCallback)(JabberIBBSession *); 37 | typedef void (JabberIBBErrorCallback)(JabberIBBSession *); 38 | typedef void (JabberIBBSentCallback)(JabberIBBSession *); 39 | 40 | typedef gboolean (JabberIBBOpenHandler)(JabberStream *js, const char *from, 41 | const char *id, xmlnode *open); 42 | 43 | typedef enum { 44 | JABBER_IBB_SESSION_NOT_OPENED, 45 | JABBER_IBB_SESSION_OPENED, 46 | JABBER_IBB_SESSION_CLOSED, 47 | JABBER_IBB_SESSION_ERROR 48 | } JabberIBBSessionState; 49 | 50 | struct _JabberIBBSession { 51 | JabberStream *js; 52 | gchar *who; 53 | gchar *sid; 54 | gchar *id; 55 | guint16 send_seq; 56 | guint16 recv_seq; 57 | gsize block_size; 58 | 59 | /* session state */ 60 | JabberIBBSessionState state; 61 | 62 | /* user data (f.ex. a handle to a PurpleXfer) */ 63 | gpointer user_data; 64 | 65 | /* callbacks */ 66 | JabberIBBOpenedCallback *opened_cb; 67 | JabberIBBSentCallback *data_sent_cb; 68 | JabberIBBClosedCallback *closed_cb; 69 | /* callback for receiving data */ 70 | JabberIBBDataCallback *data_received_cb; 71 | JabberIBBErrorCallback *error_cb; 72 | 73 | /* store the last sent IQ (to permit cancel of callback) */ 74 | gchar *last_iq_id; 75 | }; 76 | 77 | JabberIBBSession *jabber_ibb_session_create(JabberStream *js, const gchar *sid, 78 | const gchar *who, gpointer user_data); 79 | JabberIBBSession *jabber_ibb_session_create_from_xmlnode(JabberStream *js, 80 | const gchar *from, const gchar *id, xmlnode *open, gpointer user_data); 81 | 82 | void jabber_ibb_session_destroy(JabberIBBSession *sess); 83 | 84 | void jabber_ibb_session_set_opened_callback(JabberIBBSession *sess, 85 | JabberIBBOpenedCallback *cb); 86 | void jabber_ibb_session_set_data_sent_callback(JabberIBBSession *sess, 87 | JabberIBBSentCallback *cb); 88 | void jabber_ibb_session_set_closed_callback(JabberIBBSession *sess, 89 | JabberIBBClosedCallback *cb); 90 | void jabber_ibb_session_set_data_received_callback(JabberIBBSession *sess, 91 | JabberIBBDataCallback *cb); 92 | void jabber_ibb_session_set_error_callback(JabberIBBSession *sess, 93 | JabberIBBErrorCallback *cb); 94 | 95 | void jabber_ibb_session_open(JabberIBBSession *sess); 96 | void jabber_ibb_session_close(JabberIBBSession *sess); 97 | void jabber_ibb_session_accept(JabberIBBSession *sess); 98 | void jabber_ibb_session_send_data(JabberIBBSession *sess, gconstpointer data, 99 | gsize size); 100 | 101 | const gchar *jabber_ibb_session_get_sid(const JabberIBBSession *sess); 102 | JabberStream *jabber_ibb_session_get_js(JabberIBBSession *sess); 103 | const gchar *jabber_ibb_session_get_who(const JabberIBBSession *sess); 104 | 105 | guint16 jabber_ibb_session_get_send_seq(const JabberIBBSession *sess); 106 | guint16 jabber_ibb_session_get_recv_seq(const JabberIBBSession *sess); 107 | 108 | JabberIBBSessionState jabber_ibb_session_get_state(const JabberIBBSession *sess); 109 | 110 | gsize jabber_ibb_session_get_block_size(const JabberIBBSession *sess); 111 | void jabber_ibb_session_set_block_size(JabberIBBSession *sess, gsize size); 112 | 113 | /* get maximum size data block to send (in bytes) 114 | (before encoded to BASE64) */ 115 | gsize jabber_ibb_session_get_max_data_size(const JabberIBBSession *sess); 116 | 117 | gpointer jabber_ibb_session_get_user_data(JabberIBBSession *sess); 118 | 119 | /* handle incoming packet */ 120 | void jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type, 121 | const char *id, xmlnode *child); 122 | 123 | /* add a handler for open session */ 124 | void jabber_ibb_register_open_handler(JabberIBBOpenHandler *cb); 125 | void jabber_ibb_unregister_open_handler(JabberIBBOpenHandler *cb); 126 | 127 | void jabber_ibb_init(void); 128 | void jabber_ibb_uninit(void); 129 | 130 | #endif /* PURPLE_JABBER_IBB_H_ */ 131 | -------------------------------------------------------------------------------- /headers/jabber/iq.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file iq.h JabberID handlers 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_IQ_H_ 25 | #define PURPLE_JABBER_IQ_H_ 26 | 27 | typedef enum { 28 | JABBER_IQ_SET, 29 | JABBER_IQ_GET, 30 | JABBER_IQ_RESULT, 31 | JABBER_IQ_ERROR, 32 | JABBER_IQ_NONE 33 | } JabberIqType; 34 | 35 | #include "jabber.h" 36 | #include "connection.h" 37 | 38 | typedef struct _JabberIq JabberIq; 39 | typedef struct _JabberIqCallbackData JabberIqCallbackData; 40 | 41 | /** 42 | * A JabberIqHandler is called to process an incoming IQ stanza. 43 | * Handlers typically process unsolicited incoming GETs or SETs for their 44 | * registered namespace, but may be called to handle the results of a 45 | * GET or SET that we generated if no JabberIqCallback was generated 46 | * The handler may be called for the results of a GET or SET (RESULT or ERROR) 47 | * that we generated 48 | * if the generating function did not register a JabberIqCallback. 49 | * 50 | * @param js The JabberStream object. 51 | * @param from The remote entity (the from attribute on the stanza) 52 | * @param type The IQ type. 53 | * @param id The IQ id (the id attribute on the stanza) 54 | * @param child The child element of the stanza that matches the name 55 | * and namespace registered with jabber_iq_register_handler. 56 | * 57 | * @see jabber_iq_register_handler() 58 | * @see JabberIqCallback 59 | */ 60 | typedef void (JabberIqHandler)(JabberStream *js, const char *from, 61 | JabberIqType type, const char *id, 62 | xmlnode *child); 63 | 64 | /** 65 | * A JabberIqCallback is called to process the results of a GET or SET that 66 | * we send to a remote entity. The callback is matched based on the id 67 | * of the incoming stanza (which matches the one on the initial stanza). 68 | * 69 | * @param js The JabberStream object. 70 | * @param from The remote entity (the from attribute on the stanza) 71 | * @param type The IQ type. The only possible values are JABBER_IQ_RESULT 72 | * and JABBER_IQ_ERROR. 73 | * @param id The IQ id (the id attribute on the stanza) 74 | * @param packet The stanza 75 | * @param data The callback data passed to jabber_iq_set_callback() 76 | * 77 | * @see jabber_iq_set_callback() 78 | */ 79 | typedef void (JabberIqCallback)(JabberStream *js, const char *from, 80 | JabberIqType type, const char *id, 81 | xmlnode *packet, gpointer data); 82 | 83 | struct _JabberIq { 84 | JabberIqType type; 85 | char *id; 86 | xmlnode *node; 87 | 88 | JabberIqCallback *callback; 89 | gpointer callback_data; 90 | 91 | JabberStream *js; 92 | }; 93 | 94 | JabberIq *jabber_iq_new(JabberStream *js, JabberIqType type); 95 | JabberIq *jabber_iq_new_query(JabberStream *js, JabberIqType type, 96 | const char *xmlns); 97 | 98 | void jabber_iq_parse(JabberStream *js, xmlnode *packet); 99 | 100 | void jabber_iq_callbackdata_free(JabberIqCallbackData *jcd); 101 | void jabber_iq_remove_callback_by_id(JabberStream *js, const char *id); 102 | void jabber_iq_set_callback(JabberIq *iq, JabberIqCallback *cb, gpointer data); 103 | void jabber_iq_set_id(JabberIq *iq, const char *id); 104 | 105 | void jabber_iq_send(JabberIq *iq); 106 | void jabber_iq_free(JabberIq *iq); 107 | 108 | void jabber_iq_init(void); 109 | void jabber_iq_uninit(void); 110 | 111 | void jabber_iq_register_handler(const char *node, const char *xmlns, 112 | JabberIqHandler *func); 113 | 114 | /* Connected to namespace-handler registration signals */ 115 | void jabber_iq_signal_register(const gchar *node, const gchar *xmlns); 116 | void jabber_iq_signal_unregister(const gchar *node, const gchar *xmlns); 117 | 118 | #endif /* PURPLE_JABBER_IQ_H_ */ 119 | -------------------------------------------------------------------------------- /headers/jabber/jabber.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file jabber.h 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_H_ 25 | #define PURPLE_JABBER_H_ 26 | 27 | typedef enum { 28 | JABBER_CAP_NONE = 0, 29 | /* JABBER_CAP_XHTML = 1 << 0, */ 30 | /* JABBER_CAP_COMPOSING = 1 << 1, */ 31 | JABBER_CAP_SI = 1 << 2, 32 | JABBER_CAP_SI_FILE_XFER = 1 << 3, 33 | JABBER_CAP_BYTESTREAMS = 1 << 4, 34 | JABBER_CAP_IBB = 1 << 5, 35 | JABBER_CAP_CHAT_STATES = 1 << 6, 36 | JABBER_CAP_IQ_SEARCH = 1 << 7, 37 | JABBER_CAP_IQ_REGISTER = 1 << 8, 38 | 39 | /* Google Talk extensions: 40 | * http://code.google.com/apis/talk/jep_extensions/extensions.html 41 | */ 42 | JABBER_CAP_GMAIL_NOTIFY = 1 << 9, 43 | JABBER_CAP_GOOGLE_ROSTER = 1 << 10, 44 | 45 | JABBER_CAP_PING = 1 << 11, 46 | JABBER_CAP_ADHOC = 1 << 12, 47 | JABBER_CAP_BLOCKING = 1 << 13, 48 | 49 | JABBER_CAP_ITEMS = 1 << 14, 50 | JABBER_CAP_ROSTER_VERSIONING = 1 << 15, 51 | 52 | JABBER_CAP_FACEBOOK = 1 << 16, 53 | 54 | JABBER_CAP_RETRIEVED = 1 << 31 55 | } JabberCapabilities; 56 | 57 | typedef struct _JabberStream JabberStream; 58 | 59 | #include 60 | #include 61 | #include "circbuffer.h" 62 | #include "connection.h" 63 | #include "dnsquery.h" 64 | #include "dnssrv.h" 65 | #include "media.h" 66 | #include "mediamanager.h" 67 | #include "roomlist.h" 68 | #include "sslconn.h" 69 | 70 | #include "namespaces.h" 71 | 72 | #include "auth.h" 73 | #include "iq.h" 74 | #include "jutil.h" 75 | #include "xmlnode.h" 76 | #include "buddy.h" 77 | #include "bosh.h" 78 | 79 | #ifdef HAVE_CYRUS_SASL 80 | #include 81 | #endif 82 | 83 | #define CAPS0115_NODE "http://pidgin.im/" 84 | 85 | #define JABBER_DEFAULT_REQUIRE_TLS "require_starttls" 86 | #define JABBER_DEFAULT_FT_PROXIES "proxy.eu.jabber.org" 87 | 88 | /* Index into attention_types list */ 89 | #define JABBER_BUZZ 0 90 | 91 | typedef enum { 92 | JABBER_STREAM_OFFLINE, 93 | JABBER_STREAM_CONNECTING, 94 | JABBER_STREAM_INITIALIZING, 95 | JABBER_STREAM_INITIALIZING_ENCRYPTION, 96 | JABBER_STREAM_AUTHENTICATING, 97 | JABBER_STREAM_POST_AUTH, 98 | JABBER_STREAM_CONNECTED 99 | } JabberStreamState; 100 | 101 | struct _JabberStream 102 | { 103 | int fd; 104 | 105 | PurpleSrvTxtQueryData *srv_query_data; 106 | 107 | xmlParserCtxt *context; 108 | xmlnode *current; 109 | 110 | struct { 111 | guint8 major; 112 | guint8 minor; 113 | } protocol_version; 114 | 115 | JabberSaslMech *auth_mech; 116 | gpointer auth_mech_data; 117 | 118 | /** 119 | * The header from the opening tag. This being NULL is treated 120 | * as a special condition in the parsing code (signifying the next 121 | * stanza started is an opening stream tag), and its being missing on 122 | * the stream header is treated as a fatal error. 123 | */ 124 | char *stream_id; 125 | JabberStreamState state; 126 | 127 | GHashTable *buddies; 128 | 129 | /* 130 | * This boolean was added to eliminate a heinous bug where we would 131 | * get into a loop with the server and move a buddy back and forth 132 | * from one group to another. 133 | * 134 | * The sequence goes something like this: 135 | * 1. Our resource and another resource both approve an authorization 136 | * request at the exact same time. We put the buddy in group A and 137 | * the other resource put the buddy in group B. 138 | * 2. The server receives the roster add for group B and sends us a 139 | * roster push. 140 | * 3. We receive this roster push and modify our local blist. This 141 | * triggers us to send a roster add for group B. 142 | * 4. The server recieves our earlier roster add for group A and sends 143 | * us a roster push. 144 | * 5. We receive this roster push and modify our local blist. This 145 | * triggers us to send a roster add for group A. 146 | * 6. The server receives our earlier roster add for group B and sends 147 | * us a roster push. 148 | * (repeat steps 3 through 6 ad infinitum) 149 | * 150 | * This boolean is used to short-circuit the sending of a roster add 151 | * when we receive a roster push. 152 | * 153 | * See these bug reports: 154 | * http://trac.adiumx.com/ticket/8834 155 | * http://developer.pidgin.im/ticket/5484 156 | * http://developer.pidgin.im/ticket/6188 157 | */ 158 | gboolean currently_parsing_roster_push; 159 | 160 | GHashTable *chats; 161 | GList *chat_servers; 162 | PurpleRoomlist *roomlist; 163 | GList *user_directories; 164 | 165 | GHashTable *iq_callbacks; 166 | int next_id; 167 | 168 | GList *bs_proxies; 169 | GList *oob_file_transfers; 170 | GList *file_transfers; 171 | 172 | time_t idle; 173 | time_t old_idle; 174 | 175 | /** When we last pinged the server, so we don't ping more 176 | * often than once every minute. 177 | */ 178 | time_t last_ping; 179 | 180 | JabberID *user; 181 | JabberBuddy *user_jb; 182 | 183 | PurpleConnection *gc; 184 | PurpleSslConnection *gsc; 185 | 186 | gboolean registration; 187 | 188 | char *initial_avatar_hash; 189 | char *avatar_hash; 190 | GSList *pending_avatar_requests; 191 | 192 | GSList *pending_buddy_info_requests; 193 | 194 | PurpleCircBuffer *write_buffer; 195 | guint writeh; 196 | 197 | gboolean reinit; 198 | 199 | JabberCapabilities server_caps; 200 | gboolean googletalk; 201 | char *server_name; 202 | 203 | char *gmail_last_time; 204 | char *gmail_last_tid; 205 | 206 | char *serverFQDN; 207 | 208 | #ifdef HAVE_CYRUS_SASL 209 | sasl_conn_t *sasl; 210 | sasl_callback_t *sasl_cb; 211 | sasl_secret_t *sasl_secret; 212 | const char *current_mech; 213 | int auth_fail_count; 214 | 215 | int sasl_state; 216 | int sasl_maxbuf; 217 | GString *sasl_mechs; 218 | #endif 219 | 220 | gboolean unregistration; 221 | PurpleAccountUnregistrationCb unregistration_cb; 222 | void *unregistration_user_data; 223 | 224 | gboolean vcard_fetched; 225 | /* Timer at login to push updated avatar */ 226 | guint vcard_timer; 227 | 228 | /* Entity Capabilities hash */ 229 | char *caps_hash; 230 | 231 | /* does the local server support PEP? */ 232 | gboolean pep; 233 | 234 | /* Is Buzz enabled? */ 235 | gboolean allowBuzz; 236 | 237 | /* A list of JabberAdHocCommands supported by the server */ 238 | GList *commands; 239 | 240 | /* last presence update to check for differences */ 241 | JabberBuddyState old_state; 242 | char *old_msg; 243 | int old_priority; 244 | char *old_avatarhash; 245 | 246 | /* same for user tune */ 247 | char *old_artist; 248 | char *old_title; 249 | char *old_source; 250 | char *old_uri; 251 | int old_length; 252 | char *old_track; 253 | 254 | char *certificate_CN; 255 | 256 | /* A purple timeout tag for the keepalive */ 257 | guint keepalive_timeout; 258 | guint max_inactivity; 259 | guint inactivity_timer; 260 | 261 | PurpleSrvResponse *srv_rec; 262 | guint srv_rec_idx; 263 | guint max_srv_rec_idx; 264 | 265 | /* BOSH stuff */ 266 | PurpleBOSHConnection *bosh; 267 | 268 | /** 269 | * This linked list contains PurpleUtilFetchUrlData structs 270 | * for when we lookup buddy icons from a url 271 | */ 272 | GSList *url_datas; 273 | 274 | /* keep a hash table of JingleSessions */ 275 | GHashTable *sessions; 276 | 277 | /* maybe this should only be present when USE_VV? */ 278 | gchar *stun_ip; 279 | int stun_port; 280 | PurpleDnsQueryData *stun_query; 281 | 282 | /* stuff for Google's relay handling */ 283 | gchar *google_relay_token; 284 | gchar *google_relay_host; 285 | GList *google_relay_requests; /* the HTTP requests to get */ 286 | /* relay info */ 287 | 288 | /* facebook quirks */ 289 | gboolean facebook_roster_cleanup_performed; 290 | }; 291 | 292 | typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *namespace); 293 | 294 | typedef struct _JabberFeature 295 | { 296 | gchar *namespace; 297 | JabberFeatureEnabled *is_enabled; 298 | } JabberFeature; 299 | 300 | typedef struct _JabberIdentity 301 | { 302 | gchar *category; 303 | gchar *type; 304 | gchar *name; 305 | gchar *lang; 306 | } JabberIdentity; 307 | 308 | typedef struct _JabberBytestreamsStreamhost { 309 | char *jid; 310 | char *host; 311 | int port; 312 | char *zeroconf; 313 | } JabberBytestreamsStreamhost; 314 | 315 | /* what kind of additional features as returned from disco#info are supported? */ 316 | extern GList *jabber_features; 317 | /* A sorted list of identities advertised. Use jabber_add_identity to add 318 | * so it remains sorted. 319 | */ 320 | extern GList *jabber_identities; 321 | 322 | void jabber_stream_features_parse(JabberStream *js, xmlnode *packet); 323 | void jabber_process_packet(JabberStream *js, xmlnode **packet); 324 | void jabber_send(JabberStream *js, xmlnode *data); 325 | void jabber_send_raw(JabberStream *js, const char *data, int len); 326 | void jabber_send_signal_cb(PurpleConnection *pc, xmlnode **packet, 327 | gpointer unused); 328 | 329 | void jabber_stream_set_state(JabberStream *js, JabberStreamState state); 330 | 331 | void jabber_register_parse(JabberStream *js, const char *from, 332 | JabberIqType type, const char *id, xmlnode *query); 333 | void jabber_register_start(JabberStream *js); 334 | 335 | char *jabber_get_next_id(JabberStream *js); 336 | 337 | /** Parse an error into a human-readable string and optionally a disconnect 338 | * reason. 339 | * @param js the stream on which the error occurred. 340 | * @param packet the error packet 341 | * @param reason where to store the disconnection reason, or @c NULL if you 342 | * don't care or you don't intend to close the connection. 343 | */ 344 | char *jabber_parse_error(JabberStream *js, xmlnode *packet, PurpleConnectionError *reason); 345 | 346 | /** 347 | * Add a feature to the list of features advertised via disco#info. If you 348 | * call this while accounts are connected, Bad Things(TM) will happen because 349 | * the Entity Caps hash will be out-of-date (which should be fixed :/) 350 | * 351 | * @param namespace The namespace of the feature 352 | * @param cb A callback determining whether or not this feature 353 | * will advertised; may be NULL. 354 | */ 355 | void jabber_add_feature(const gchar *namespace, JabberFeatureEnabled cb); 356 | void jabber_remove_feature(const gchar *namespace); 357 | 358 | /** Adds an identity to this jabber library instance. For list of valid values 359 | * visit the website of the XMPP Registrar 360 | * (http://www.xmpp.org/registrar/disco-categories.html#client). 361 | * 362 | * Like with jabber_add_feature, if you call this while accounts are connected, 363 | * Bad Things will happen. 364 | * 365 | * @param category the category of the identity. 366 | * @param type the type of the identity. 367 | * @param language the language localization of the name. Can be NULL. 368 | * @param name the name of the identity. 369 | */ 370 | void jabber_add_identity(const gchar *category, const gchar *type, const gchar *lang, const gchar *name); 371 | 372 | /** 373 | * GCompareFunc for JabberIdentity structs. 374 | */ 375 | gint jabber_identity_compare(gconstpointer a, gconstpointer b); 376 | 377 | /** 378 | * Returns true if this connection is over a secure (SSL) stream. Use this 379 | * instead of checking js->gsc because BOSH stores its PurpleSslConnection 380 | * members in its own data structure. 381 | */ 382 | gboolean jabber_stream_is_ssl(JabberStream *js); 383 | 384 | /** 385 | * Restart the "we haven't sent anything in a while and should send 386 | * something or the server will kick us off" timer (obviously 387 | * called when sending something. It's exposed for BOSH.) 388 | */ 389 | void jabber_stream_restart_inactivity_timer(JabberStream *js); 390 | 391 | /** PRPL functions */ 392 | const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b); 393 | const char* jabber_list_emblem(PurpleBuddy *b); 394 | char *jabber_status_text(PurpleBuddy *b); 395 | void jabber_tooltip_text(PurpleBuddy *b, PurpleNotifyUserInfo *user_info, gboolean full); 396 | GList *jabber_status_types(PurpleAccount *account); 397 | void jabber_login(PurpleAccount *account); 398 | void jabber_close(PurpleConnection *gc); 399 | void jabber_idle_set(PurpleConnection *gc, int idle); 400 | void jabber_blocklist_parse_push(JabberStream *js, const char *from, 401 | JabberIqType type, const char *id, 402 | xmlnode *child); 403 | void jabber_request_block_list(JabberStream *js); 404 | void jabber_add_deny(PurpleConnection *gc, const char *who); 405 | void jabber_rem_deny(PurpleConnection *gc, const char *who); 406 | void jabber_keepalive(PurpleConnection *gc); 407 | void jabber_register_gateway(JabberStream *js, const char *gateway); 408 | void jabber_register_account(PurpleAccount *account); 409 | void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data); 410 | gboolean jabber_send_attention(PurpleConnection *gc, const char *username, guint code); 411 | GList *jabber_attention_types(PurpleAccount *account); 412 | void jabber_convo_closed(PurpleConnection *gc, const char *who); 413 | PurpleChat *jabber_find_blist_chat(PurpleAccount *account, const char *name); 414 | gboolean jabber_offline_message(const PurpleBuddy *buddy); 415 | int jabber_prpl_send_raw(PurpleConnection *gc, const char *buf, int len); 416 | GList *jabber_actions(PurplePlugin *plugin, gpointer context); 417 | 418 | gboolean jabber_audio_enabled(JabberStream *js, const char *unused); 419 | gboolean jabber_video_enabled(JabberStream *js, const char *unused); 420 | gboolean jabber_initiate_media(PurpleAccount *account, const char *who, 421 | PurpleMediaSessionType type); 422 | PurpleMediaCaps jabber_get_media_caps(PurpleAccount *account, const char *who); 423 | gboolean jabber_can_receive_file(PurpleConnection *gc, const gchar *who); 424 | 425 | void jabber_plugin_init(PurplePlugin *plugin); 426 | void jabber_plugin_uninit(PurplePlugin *plugin); 427 | 428 | #endif /* PURPLE_JABBER_H_ */ 429 | -------------------------------------------------------------------------------- /headers/jabber/jutil.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file jutil.h utility functions 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_JUTIL_H_ 25 | #define PURPLE_JABBER_JUTIL_H_ 26 | 27 | typedef struct _JabberID { 28 | char *node; 29 | char *domain; 30 | char *resource; 31 | } JabberID; 32 | 33 | typedef enum { 34 | JABBER_BUDDY_STATE_UNKNOWN = -2, 35 | JABBER_BUDDY_STATE_ERROR = -1, 36 | JABBER_BUDDY_STATE_UNAVAILABLE = 0, 37 | JABBER_BUDDY_STATE_ONLINE, 38 | JABBER_BUDDY_STATE_CHAT, 39 | JABBER_BUDDY_STATE_AWAY, 40 | JABBER_BUDDY_STATE_XA, 41 | JABBER_BUDDY_STATE_DND 42 | } JabberBuddyState; 43 | 44 | #include "jabber.h" 45 | 46 | JabberID* jabber_id_new(const char *str); 47 | 48 | /** 49 | * Compare two JIDs for equality. In addition to the node and domain, 50 | * the resources of the two JIDs must also be equal (or both absent). 51 | */ 52 | gboolean jabber_id_equal(const JabberID *jid1, const JabberID *jid2); 53 | 54 | void jabber_id_free(JabberID *jid); 55 | 56 | char *jabber_get_domain(const char *jid); 57 | char *jabber_get_resource(const char *jid); 58 | char *jabber_get_bare_jid(const char *jid); 59 | char *jabber_id_get_bare_jid(const JabberID *jid); 60 | char *jabber_id_get_full_jid(const JabberID *jid); 61 | JabberID *jabber_id_to_bare_jid(const JabberID *jid); 62 | 63 | gboolean jabber_jid_is_domain(const char *jid); 64 | 65 | const char *jabber_normalize(const PurpleAccount *account, const char *in); 66 | 67 | /* Returns true if JID is the bare JID of our server. */ 68 | gboolean jabber_is_own_server(JabberStream *js, const char *jid); 69 | 70 | /* Returns true if JID is the bare JID of our account. */ 71 | gboolean jabber_is_own_account(JabberStream *js, const char *jid); 72 | 73 | gboolean jabber_nodeprep_validate(const char *); 74 | gboolean jabber_domain_validate(const char *); 75 | gboolean jabber_resourceprep_validate(const char *); 76 | 77 | /** 78 | * Apply the SASLprep profile of stringprep to the string passed in. 79 | * 80 | * @returns A newly allocated string containing the normalized version 81 | * of the input, or NULL if an error occurred (the string could 82 | * not be normalized) 83 | */ 84 | char *jabber_saslprep(const char *); 85 | 86 | /* state -> readable name */ 87 | const char *jabber_buddy_state_get_name(JabberBuddyState state); 88 | /* state -> core id */ 89 | const char *jabber_buddy_state_get_status_id(JabberBuddyState state); 90 | /* state -> show attr (for presence stanza) */ 91 | const char *jabber_buddy_state_get_show(JabberBuddyState state); 92 | /* core id -> state */ 93 | JabberBuddyState jabber_buddy_status_id_get_state(const char *id); 94 | /* show attr (presence stanza) -> state */ 95 | JabberBuddyState jabber_buddy_show_get_state(const char *id); 96 | 97 | char *jabber_calculate_data_hash(gconstpointer data, size_t len, 98 | const gchar *hash_algo); 99 | #endif /* PURPLE_JABBER_JUTIL_H_ */ 100 | -------------------------------------------------------------------------------- /headers/jabber/message.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file message.h Message handlers 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_MESSAGE_H_ 25 | #define PURPLE_JABBER_MESSAGE_H_ 26 | 27 | #include "buddy.h" 28 | #include "jabber.h" 29 | #include "xmlnode.h" 30 | 31 | typedef struct _JabberMessage { 32 | JabberStream *js; 33 | enum { 34 | JABBER_MESSAGE_NORMAL, 35 | JABBER_MESSAGE_CHAT, 36 | JABBER_MESSAGE_GROUPCHAT, 37 | JABBER_MESSAGE_HEADLINE, 38 | JABBER_MESSAGE_ERROR, 39 | JABBER_MESSAGE_GROUPCHAT_INVITE, 40 | JABBER_MESSAGE_EVENT, 41 | JABBER_MESSAGE_OTHER 42 | } type; 43 | time_t sent; 44 | gboolean delayed; 45 | gboolean hasBuzz; 46 | char *id; 47 | char *from; 48 | char *to; 49 | char *subject; 50 | char *body; 51 | char *xhtml; 52 | char *password; 53 | char *error; 54 | char *thread_id; 55 | enum { 56 | JM_STATE_NONE, 57 | JM_STATE_ACTIVE, 58 | JM_STATE_COMPOSING, 59 | JM_STATE_PAUSED, 60 | JM_STATE_INACTIVE, 61 | JM_STATE_GONE 62 | } chat_state; 63 | GList *etc; 64 | GList *eventitems; 65 | } JabberMessage; 66 | 67 | void jabber_message_free(JabberMessage *jm); 68 | 69 | void jabber_message_send(JabberMessage *jm); 70 | 71 | void jabber_message_parse(JabberStream *js, xmlnode *packet); 72 | int jabber_message_send_im(PurpleConnection *gc, const char *who, const char *msg, 73 | PurpleMessageFlags flags); 74 | int jabber_message_send_chat(PurpleConnection *gc, int id, const char *message, PurpleMessageFlags flags); 75 | 76 | unsigned int jabber_send_typing(PurpleConnection *gc, const char *who, PurpleTypingState state); 77 | 78 | gboolean jabber_buzz_isenabled(JabberStream *js, const gchar *namespace); 79 | 80 | gboolean jabber_custom_smileys_isenabled(JabberStream *js, const const gchar *namespace); 81 | 82 | #endif /* PURPLE_JABBER_MESSAGE_H_ */ 83 | -------------------------------------------------------------------------------- /headers/jabber/namespaces.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_NAMESPACES_H_ 25 | #define PURPLE_JABBER_NAMESPACES_H_ 26 | 27 | #define NS_XMPP_BIND "urn:ietf:params:xml:ns:xmpp-bind" 28 | #define NS_XMPP_CLIENT "jabber:client" 29 | #define NS_XMPP_SASL "urn:ietf:params:xml:ns:xmpp-sasl" 30 | #define NS_XMPP_SESSION "urn:ietf:params:xml:ns:xmpp-session" 31 | #define NS_XMPP_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas" 32 | #define NS_XMPP_STREAMS "http://etherx.jabber.org/streams" 33 | #define NS_XMPP_TLS "urn:ietf:params:xml:ns:xmpp-tls" 34 | 35 | /* XEP-0012 Last Activity (and XEP-0256 Last Activity in Presence) */ 36 | #define NS_LAST_ACTIVITY "jabber:iq:last" 37 | 38 | /* XEP-0030 Service Discovery */ 39 | #define NS_DISCO_INFO "http://jabber.org/protocol/disco#info" 40 | #define NS_DISCO_ITEMS "http://jabber.org/protocol/disco#items" 41 | 42 | /* XEP-0047 IBB (In-band bytestreams) */ 43 | #define NS_IBB "http://jabber.org/protocol/ibb" 44 | 45 | /* XEP-0065 SOCKS5 Bytestreams */ 46 | #define NS_BYTESTREAMS "http://jabber.org/protocol/bytestreams" 47 | 48 | /* XEP-0066 Out of Band Data (OOB) */ 49 | #define NS_OOB_IQ_DATA "jabber:iq:oob" 50 | #define NS_OOB_X_DATA "jabber:x:oob" 51 | 52 | /* XEP-0071 XHTML-IM (rich-text messages) */ 53 | #define NS_XHTML_IM "http://jabber.org/protocol/xhtml-im" 54 | #define NS_XHTML "http://www.w3.org/1999/xhtml" 55 | 56 | /* XEP-0084 v0.12 User Avatar */ 57 | #define NS_AVATAR_0_12_DATA "http://www.xmpp.org/extensions/xep-0084.html#ns-data" 58 | #define NS_AVATAR_0_12_METADATA "http://www.xmpp.org/extensions/xep-0084.html#ns-metadata" 59 | 60 | /* XEP-0084 v1.1 User Avatar */ 61 | #define NS_AVATAR_1_1_DATA "urn:xmpp:avatar:data" 62 | #define NS_AVATAR_1_1_METADATA "urn:xmpp:avatar:metadata" 63 | 64 | /* XEP-0096 SI File Transfer */ 65 | #define NS_SI_FILE_TRANSFER "http://jabber.org/protocol/si/profile/file-transfer" 66 | 67 | /* XEP-0124 Bidirectional-streams Over Synchronous HTTP (BOSH) */ 68 | #define NS_BOSH "http://jabber.org/protocol/httpbind" 69 | 70 | /* XEP-0191 Simple Communications Blocking */ 71 | #define NS_SIMPLE_BLOCKING "urn:xmpp:blocking" 72 | 73 | /* XEP-0199 Ping */ 74 | #define NS_PING "urn:xmpp:ping" 75 | 76 | /* XEP-0202 Entity Time */ 77 | #define NS_ENTITY_TIME "urn:xmpp:time" 78 | 79 | /* XEP-0203 Delayed Delivery (and legacy delayed delivery) */ 80 | #define NS_DELAYED_DELIVERY "urn:xmpp:delay" 81 | #define NS_DELAYED_DELIVERY_LEGACY "jabber:x:delay" 82 | 83 | /* XEP-0206 XMPP over BOSH */ 84 | #define NS_XMPP_BOSH "urn:xmpp:xbosh" 85 | 86 | /* XEP-0224 Attention */ 87 | #define NS_ATTENTION "urn:xmpp:attention:0" 88 | 89 | /* XEP-0231 BoB (Bits of Binary) */ 90 | #define NS_BOB "urn:xmpp:bob" 91 | 92 | /* XEP-0237 Roster Versioning */ 93 | #define NS_ROSTER_VERSIONING "urn:xmpp:features:rosterver" 94 | 95 | /* XEP-0264 File Transfer Thumbnails (Thumbs) */ 96 | #define NS_THUMBS "urn:xmpp:thumbs:0" 97 | 98 | /* Google extensions */ 99 | #define NS_GOOGLE_CAMERA "http://www.google.com/xmpp/protocol/camera/v1" 100 | #define NS_GOOGLE_VIDEO "http://www.google.com/xmpp/protocol/video/v1" 101 | #define NS_GOOGLE_VOICE "http://www.google.com/xmpp/protocol/voice/v1" 102 | #define NS_GOOGLE_JINGLE_INFO "google:jingleinfo" 103 | 104 | #define NS_GOOGLE_MAIL_NOTIFY "google:mail:notify" 105 | #define NS_GOOGLE_ROSTER "google:roster" 106 | 107 | #define NS_GOOGLE_PROTOCOL_SESSION "http://www.google.com/xmpp/protocol/session" 108 | #define NS_GOOGLE_SESSION "http://www.google.com/session" 109 | #define NS_GOOGLE_SESSION_PHONE "http://www.google.com/session/phone" 110 | #define NS_GOOGLE_SESSION_VIDEO "http://www.google.com/session/video" 111 | 112 | #endif /* PURPLE_JABBER_NAMESPACES_H_ */ 113 | -------------------------------------------------------------------------------- /headers/jabber/oob.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file oob.h out-of-band transfer functions 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_OOB_H_ 25 | #define PURPLE_JABBER_OOB_H_ 26 | 27 | #include "jabber.h" 28 | 29 | void jabber_oob_parse(JabberStream *js, const char *from, JabberIqType type, 30 | const char *id, xmlnode *querynode); 31 | 32 | #endif /* PURPLE_JABBER_OOB_H_ */ 33 | -------------------------------------------------------------------------------- /headers/jabber/parser.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file parser.h XML parser functions 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_PARSER_H_ 25 | #define PURPLE_JABBER_PARSER_H_ 26 | 27 | #include "jabber.h" 28 | 29 | void jabber_parser_setup(JabberStream *js); 30 | void jabber_parser_free(JabberStream *js); 31 | void jabber_parser_process(JabberStream *js, const char *buf, int len); 32 | 33 | #endif /* PURPLE_JABBER_PARSER_H_ */ 34 | -------------------------------------------------------------------------------- /headers/jabber/pep.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_PEP_H_ 25 | #define PURPLE_JABBER_PEP_H_ 26 | 27 | #include "jabber.h" 28 | #include "message.h" 29 | #include "buddy.h" 30 | 31 | void jabber_pep_init(void); 32 | void jabber_pep_uninit(void); 33 | 34 | void jabber_pep_init_actions(GList **m); 35 | 36 | /* 37 | * Callback for receiving PEP events. 38 | * 39 | * @parameter js The JabberStream this item was received on 40 | * @parameter items The <items/>-tag with the <item/>-children 41 | */ 42 | typedef void (JabberPEPHandler)(JabberStream *js, const char *from, xmlnode *items); 43 | 44 | /* 45 | * Registers a callback for PEP events. Also automatically announces this receiving capability via disco#info. 46 | * Don't forget to use jabber_add_feature when supporting the sending of PEP events of this type. 47 | * 48 | * @parameter xmlns The namespace for this event 49 | * @parameter handlerfunc The callback to be used when receiving an event with this namespace 50 | */ 51 | void jabber_pep_register_handler(const char *xmlns, JabberPEPHandler handlerfunc); 52 | 53 | /* 54 | * Request a specific item from another PEP node. 55 | * 56 | * @parameter js The JabberStream that should be used 57 | * @parameter to The target PEP node 58 | * @parameter node The node name of the item that is requested 59 | * @parameter id The item id of the requested item (may be NULL) 60 | * @parameter cb The callback to be used when this item is received 61 | * 62 | * The items element passed to the callback will be NULL if any error occurred (like a permission error, node doesn't exist etc.) 63 | */ 64 | void jabber_pep_request_item(JabberStream *js, const char *to, const char *node, const char *id, JabberPEPHandler cb); 65 | 66 | /* 67 | * Default callback that can be used for namespaces which should only be enabled when PEP is supported 68 | * 69 | * @parameter js The JabberStream struct for this connection 70 | * @parameter namespace The namespace that's queried, ignored. 71 | * 72 | * @returns TRUE when PEP is enabled, FALSE otherwise 73 | */ 74 | gboolean jabber_pep_namespace_only_when_pep_enabled_cb(JabberStream *js, const gchar *namespace); 75 | 76 | void jabber_handle_event(JabberMessage *jm); 77 | 78 | /** 79 | * Delete the specified PEP node. 80 | */ 81 | void jabber_pep_delete_node(JabberStream *js, const gchar *node); 82 | 83 | /* 84 | * Publishes PEP item(s) 85 | * 86 | * @parameter js The JabberStream associated with the connection this event should be published 87 | * @parameter publish The publish node. This could be for example <publish node='http://jabber.org/protocol/tune'/> with an <item/> as subnode 88 | */ 89 | void jabber_pep_publish(JabberStream *js, xmlnode *publish); 90 | 91 | #endif /* PURPLE_JABBER_PEP_H_ */ 92 | -------------------------------------------------------------------------------- /headers/jabber/ping.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ping.h ping functions 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_PING_H_ 25 | #define PURPLE_JABBER_PING_H_ 26 | 27 | #include "jabber.h" 28 | #include "iq.h" 29 | #include "xmlnode.h" 30 | 31 | void jabber_ping_parse(JabberStream *js, const char *from, 32 | JabberIqType, const char *id, xmlnode *child); 33 | gboolean jabber_ping_jid(JabberStream *js, const char *jid); 34 | void jabber_keepalive_ping(JabberStream *js); 35 | 36 | #endif /* PURPLE_JABBER_PING_H_ */ 37 | -------------------------------------------------------------------------------- /headers/jabber/presence.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file presence.h Presence 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_PRESENCE_H_ 25 | #define PURPLE_JABBER_PRESENCE_H_ 26 | 27 | typedef enum { 28 | JABBER_PRESENCE_ERROR = -2, 29 | JABBER_PRESENCE_PROBE = -1, 30 | JABBER_PRESENCE_AVAILABLE, 31 | JABBER_PRESENCE_UNAVAILABLE, 32 | JABBER_PRESENCE_SUBSCRIBE, 33 | JABBER_PRESENCE_SUBSCRIBED, 34 | JABBER_PRESENCE_UNSUBSCRIBE, 35 | JABBER_PRESENCE_UNSUBSCRIBED 36 | } JabberPresenceType; 37 | 38 | typedef struct _JabberPresenceChatInfo JabberPresenceChatInfo; 39 | typedef struct _JabberPresence JabberPresence; 40 | 41 | #include "buddy.h" 42 | #include "chat.h" 43 | #include "jabber.h" 44 | #include "jutil.h" 45 | #include "xmlnode.h" 46 | 47 | struct _JabberPresenceChatInfo { 48 | GSList *codes; 49 | xmlnode *item; 50 | }; 51 | 52 | struct _JabberPresence { 53 | JabberPresenceType type; 54 | JabberID *jid_from; 55 | const char *from; 56 | const char *to; 57 | const char *id; 58 | 59 | JabberBuddy *jb; 60 | JabberChat *chat; 61 | JabberPresenceChatInfo chat_info; 62 | xmlnode *caps; /* TODO: Temporary, see presence.c:parse_caps */ 63 | 64 | JabberBuddyState state; 65 | gchar *status; 66 | int priority; 67 | 68 | char *vcard_avatar_hash; 69 | char *nickname; 70 | 71 | gboolean delayed; 72 | time_t sent; 73 | int idle; 74 | }; 75 | 76 | typedef void (JabberPresenceHandler)(JabberStream *js, JabberPresence *presence, 77 | xmlnode *child); 78 | void jabber_presence_register_handler(const char *node, const char *xmlns, 79 | JabberPresenceHandler *handler); 80 | 81 | void jabber_presence_init(void); 82 | void jabber_presence_uninit(void); 83 | 84 | void jabber_set_status(PurpleAccount *account, PurpleStatus *status); 85 | 86 | /** 87 | * Send a full presence stanza. 88 | * 89 | * @param js A JabberStream object. 90 | * @param force Force sending the presence stanza, irrespective of whether 91 | * the contents seem to have changed. 92 | */ 93 | void jabber_presence_send(JabberStream *js, gboolean force); 94 | 95 | xmlnode *jabber_presence_create(JabberBuddyState state, const char *msg, int priority); /* DEPRECATED */ 96 | xmlnode *jabber_presence_create_js(JabberStream *js, JabberBuddyState state, const char *msg, int priority); 97 | void jabber_presence_parse(JabberStream *js, xmlnode *packet); 98 | void jabber_presence_subscription_set(JabberStream *js, const char *who, 99 | const char *type); 100 | void jabber_presence_fake_to_self(JabberStream *js, PurpleStatus *status); 101 | void purple_status_to_jabber(const PurpleStatus *status, JabberBuddyState *state, char **msg, int *priority); 102 | 103 | #endif /* PURPLE_JABBER_PRESENCE_H_ */ 104 | -------------------------------------------------------------------------------- /headers/jabber/roster.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file roster.h Roster manipulation 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_ROSTER_H_ 25 | #define PURPLE_JABBER_ROSTER_H_ 26 | 27 | /* it must *not* be localized */ 28 | #define JABBER_ROSTER_DEFAULT_GROUP "Buddies" 29 | 30 | #include "jabber.h" 31 | 32 | void jabber_roster_request(JabberStream *js); 33 | 34 | void jabber_roster_parse(JabberStream *js, const char *from, 35 | JabberIqType type, const char *id, xmlnode *query); 36 | 37 | void jabber_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy, 38 | PurpleGroup *group); 39 | void jabber_roster_alias_change(PurpleConnection *gc, const char *name, 40 | const char *alias); 41 | void jabber_roster_group_change(PurpleConnection *gc, const char *name, 42 | const char *old_group, const char *new_group); 43 | void jabber_roster_group_rename(PurpleConnection *gc, const char *old_name, 44 | PurpleGroup *group, GList *moved_buddies); 45 | void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, 46 | PurpleGroup *group); 47 | 48 | const gchar * 49 | jabber_roster_group_get_global_name(PurpleGroup *group); 50 | 51 | #endif /* PURPLE_JABBER_ROSTER_H_ */ 52 | -------------------------------------------------------------------------------- /headers/jabber/si.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file si.h SI transfer functions 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_SI_H_ 25 | #define PURPLE_JABBER_SI_H_ 26 | 27 | #include "ft.h" 28 | 29 | #include "jabber.h" 30 | 31 | void jabber_bytestreams_parse(JabberStream *js, const char *from, 32 | JabberIqType type, const char *id, xmlnode *query); 33 | void jabber_si_parse(JabberStream *js, const char *from, JabberIqType type, 34 | const char *id, xmlnode *si); 35 | PurpleXfer *jabber_si_new_xfer(PurpleConnection *gc, const char *who); 36 | void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file); 37 | void jabber_si_init(void); 38 | void jabber_si_uninit(void); 39 | 40 | #endif /* PURPLE_JABBER_SI_H_ */ 41 | -------------------------------------------------------------------------------- /headers/jabber/useravatar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef _PURPLE_JABBER_USERAVATAR_H_ 25 | #define _PURPLE_JABBER_USERAVATAR_H_ 26 | 27 | #include "jabber.h" 28 | #include "imgstore.h" 29 | 30 | /* Implementation of XEP-0084 */ 31 | 32 | void jabber_avatar_init(void); 33 | void jabber_avatar_set(JabberStream *js, PurpleStoredImage *img); 34 | 35 | void jabber_avatar_fetch_mine(JabberStream *js); 36 | 37 | #endif /* _PURPLE_JABBER_USERAVATAR_H_ */ 38 | -------------------------------------------------------------------------------- /headers/jabber/usermood.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_USERMOOD_H_ 25 | #define PURPLE_JABBER_USERMOOD_H_ 26 | 27 | #include "jabber.h" 28 | 29 | /* Implementation of XEP-0107 */ 30 | 31 | void jabber_mood_init(void); 32 | 33 | void jabber_mood_set(JabberStream *js, 34 | const char *mood, /* must be one of the valid strings defined in the XEP */ 35 | const char *text /* might be NULL */); 36 | 37 | PurpleMood *jabber_get_moods(PurpleAccount *account); 38 | 39 | #endif /* PURPLE_JABBER_USERMOOD_H_ */ 40 | -------------------------------------------------------------------------------- /headers/jabber/usernick.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_USERNICK_H_ 25 | #define PURPLE_JABBER_USERNICK_H_ 26 | 27 | #include "jabber.h" 28 | 29 | /* Implementation of XEP-0172 */ 30 | 31 | void jabber_nick_init(void); 32 | void jabber_nick_init_action(GList **m); 33 | 34 | #endif /* PURPLE_JABBER_USERNICK_H_ */ 35 | -------------------------------------------------------------------------------- /headers/jabber/usertune.h: -------------------------------------------------------------------------------- 1 | /* 2 | * purple - Jabber Protocol Plugin 3 | * 4 | * Purple is the legal property of its developers, whose names are too numerous 5 | * to list here. Please refer to the COPYRIGHT file distributed with this 6 | * source distribution. 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 21 | * 22 | */ 23 | 24 | #ifndef PURPLE_JABBER_USERTUNE_H_ 25 | #define PURPLE_JABBER_USERTUNE_H_ 26 | 27 | #include "jabber.h" 28 | 29 | /* Implementation of XEP-0118 */ 30 | 31 | typedef struct _PurpleJabberTuneInfo PurpleJabberTuneInfo; 32 | struct _PurpleJabberTuneInfo { 33 | char *artist; 34 | char *title; 35 | char *album; 36 | char *track; /* either the index of the track in the album or the URL for a stream */ 37 | int time; /* in seconds, -1 for unknown */ 38 | char *url; 39 | }; 40 | 41 | void jabber_tune_init(void); 42 | 43 | void jabber_tune_set(PurpleConnection *gc, const PurpleJabberTuneInfo *tuneinfo); 44 | 45 | #endif /* PURPLE_JABBER_USERTUNE_H_ */ 46 | -------------------------------------------------------------------------------- /headers/jabber/xdata.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file xdata.h utility functions 3 | * 4 | * purple 5 | * 6 | * Purple is the legal property of its developers, whose names are too numerous 7 | * to list here. Please refer to the COPYRIGHT file distributed with this 8 | * source distribution. 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA 23 | */ 24 | #ifndef PURPLE_JABBER_XDATA_H_ 25 | #define PURPLE_JABBER_XDATA_H_ 26 | 27 | #include "jabber.h" 28 | #include "xmlnode.h" 29 | 30 | typedef struct _JabberXDataAction { 31 | char *name; 32 | char *handle; 33 | } JabberXDataAction; 34 | 35 | typedef void (*jabber_x_data_cb)(JabberStream *js, xmlnode *result, gpointer user_data); 36 | typedef void (*jabber_x_data_action_cb)(JabberStream *js, xmlnode *result, const char *actionhandle, gpointer user_data); 37 | void *jabber_x_data_request(JabberStream *js, xmlnode *packet, jabber_x_data_cb cb, gpointer user_data); 38 | void *jabber_x_data_request_with_actions(JabberStream *js, xmlnode *packet, GList *actions, int defaultaction, jabber_x_data_action_cb cb, gpointer user_data); 39 | 40 | /* 41 | * Return the form type (the CDATA of the value child of the FORM_TYPE 42 | * field entry. 43 | * E.g., for the following, "http://jabber.org/protocol/muc#roominfo". 44 | * 45 | * 46 | * http://jabber.org/protocol/muc#roominfo 47 | * 48 | * 49 | * 50 | * @param form The xmlnode for the form (the 'x' element) 51 | * @returns The FORM_TYPE. Must be freed by caller. 52 | */ 53 | gchar *jabber_x_data_get_formtype(const xmlnode *form); 54 | 55 | #endif /* PURPLE_JABBER_XDATA_H_ */ 56 | -------------------------------------------------------------------------------- /src/carbons.c: -------------------------------------------------------------------------------- 1 | /* 2 | carbons - XEP-0280 plugin for libpurple 3 | Copyright (C) 2017, Richard Bayerle 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include "iq.h" 28 | 29 | #include "carbons.h" 30 | #include "carbons_internal.h" 31 | 32 | #define JABBER_PROTOCOL_ID "prpl-jabber" 33 | 34 | #define CARBONS_SETTING_NAME "carbons-enabled" 35 | #define CARBONS_LOG_CATEGORY "carbons" 36 | 37 | #define CARBONS_XMLNS "urn:xmpp:carbons:2" // https://xmpp.org/extensions/xep-0280.html 38 | #define DISCO_XMLNS "http://jabber.org/protocol/disco#info" // see XEP-0030: Service Discovery (https://xmpp.org/extensions/xep-0030.html) 39 | 40 | /** 41 | * From section 11, security considerations: 42 | * 'Any forwarded copies received by a Carbons-enabled client MUST be from that user's bare JID' 43 | * 44 | * If there was an attempt to fake a message, this function will return 0 and delete all children. 45 | * Otherwise it just returns 1. 46 | */ 47 | static int carbons_filter_invalid(PurpleAccount * acc_p, xmlnode * outer_msg_stanza_p) { 48 | char ** split = (void *) 0; 49 | xmlnode * curr_node_p = (void *) 0; 50 | xmlnode * temp_node_p = (void *) 0; 51 | 52 | int ret_val = 0; 53 | 54 | split = g_strsplit(purple_account_get_username(acc_p), "/", 2); 55 | 56 | if (g_strcmp0(split[0], xmlnode_get_attrib(outer_msg_stanza_p, "from"))) { 57 | purple_debug_warning(CARBONS_LOG_CATEGORY, "Invalid sender: %s (should be: %s)\n", xmlnode_get_attrib(outer_msg_stanza_p, "from"), split[0]); 58 | 59 | curr_node_p = outer_msg_stanza_p->child; 60 | while(curr_node_p) { 61 | temp_node_p = curr_node_p->next; 62 | xmlnode_free(curr_node_p); 63 | curr_node_p = temp_node_p; 64 | } 65 | 66 | ret_val = 0; 67 | } else { 68 | ret_val = 1; 69 | } 70 | 71 | g_strfreev(split); 72 | 73 | return ret_val; 74 | } 75 | 76 | void carbons_xml_received_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp) { 77 | xmlnode * carbons_node_p = (void *) 0; 78 | xmlnode * forwarded_node_p = (void *) 0; 79 | xmlnode * msg_node_p = (void *) 0; 80 | 81 | if (!stanza_pp || !(*stanza_pp)) { 82 | return; 83 | } 84 | 85 | if (g_strcmp0((*stanza_pp)->name, "message")) { 86 | return; 87 | } 88 | 89 | carbons_node_p = xmlnode_get_child_with_namespace(*stanza_pp, "received", CARBONS_XMLNS); 90 | if (carbons_node_p) { 91 | purple_debug_info(CARBONS_LOG_CATEGORY, "Received carbon copy of a received message.\n"); 92 | 93 | if (!carbons_filter_invalid(purple_connection_get_account(gc_p), *stanza_pp)) { 94 | purple_debug_warning(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of received message with invalid sender.\n"); 95 | return; 96 | } 97 | 98 | forwarded_node_p = xmlnode_get_child(carbons_node_p, "forwarded"); 99 | if (!forwarded_node_p) { 100 | purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of received message that does not contain a 'forwarded' node.\n"); 101 | return; 102 | } 103 | 104 | msg_node_p = xmlnode_get_child(forwarded_node_p, "message"); 105 | if (!msg_node_p) { 106 | purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of received message that does not contain a 'message' node.\n"); 107 | return; 108 | } 109 | 110 | msg_node_p = xmlnode_copy(msg_node_p); 111 | xmlnode_free(*stanza_pp); 112 | *stanza_pp = msg_node_p; 113 | return; 114 | } 115 | 116 | carbons_node_p = xmlnode_get_child_with_namespace(*stanza_pp, "sent", CARBONS_XMLNS); 117 | if (carbons_node_p) { 118 | purple_debug_info(CARBONS_LOG_CATEGORY, "Received carbon copy of a sent message.\n"); 119 | 120 | if (!carbons_filter_invalid(purple_connection_get_account(gc_p), *stanza_pp)) { 121 | purple_debug_warning(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of sent message with invalid sender.\n"); 122 | return; 123 | } 124 | 125 | forwarded_node_p = xmlnode_get_child(carbons_node_p, "forwarded"); 126 | if (!forwarded_node_p) { 127 | purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of sent message that does not contain a 'forwarded' node.\n"); 128 | return; 129 | } 130 | 131 | msg_node_p = xmlnode_get_child(forwarded_node_p, "message"); 132 | if (!msg_node_p) { 133 | purple_debug_error(CARBONS_LOG_CATEGORY, "Ignoring carbon copy of sent message that does not contain a 'message' node.\n"); 134 | return; 135 | } 136 | 137 | // add an empty node inside the message node for detection in later callback 138 | carbons_node_p = xmlnode_new_child(msg_node_p, "sent"); 139 | xmlnode_set_namespace(carbons_node_p, CARBONS_XMLNS); 140 | 141 | purple_debug_info(CARBONS_LOG_CATEGORY, "Stripped carbons envelope of a sent message and passing through the message stanza.\n"); 142 | msg_node_p = xmlnode_copy(msg_node_p); 143 | xmlnode_free(*stanza_pp); 144 | *stanza_pp = msg_node_p; 145 | } 146 | } 147 | 148 | // libpurple doesn't know what to do with incoming messages addressed to someone else, so they need to be written to the conversation manually 149 | // checks for presence of a node that was inserted in the initial handler 150 | void carbons_xml_stripped_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp) { 151 | xmlnode * carbons_node_p = (void *) 0; 152 | xmlnode * body_node_p = (void *) 0; 153 | char * buddy_name_bare = (void *) 0; 154 | PurpleConversation * conv_p = (void *) 0; 155 | PurpleAccount * acc_p = (void *) 0; 156 | char * body_data = (void *) 0; 157 | 158 | if (!stanza_pp || !(*stanza_pp)) { 159 | return; 160 | } 161 | 162 | if (g_strcmp0((*stanza_pp)->name, "message")) { 163 | return; 164 | } 165 | 166 | carbons_node_p = xmlnode_get_child_with_namespace(*stanza_pp, "sent", CARBONS_XMLNS); 167 | if (!carbons_node_p) { 168 | return; 169 | } 170 | 171 | body_node_p = xmlnode_get_child(*stanza_pp, "body"); 172 | if (!body_node_p) { 173 | return; 174 | } 175 | 176 | buddy_name_bare = jabber_get_bare_jid(xmlnode_get_attrib(*stanza_pp, "to")); 177 | acc_p = purple_connection_get_account(gc_p); 178 | conv_p = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy_name_bare, acc_p); 179 | if (!conv_p) { 180 | conv_p = purple_conversation_new(PURPLE_CONV_TYPE_IM, acc_p, buddy_name_bare); 181 | } 182 | 183 | 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); 184 | body_data = xmlnode_get_data(body_node_p); 185 | purple_conversation_write(conv_p, xmlnode_get_attrib(*stanza_pp, "from"), body_data, PURPLE_MESSAGE_SEND, time((void *) 0)); 186 | 187 | 188 | xmlnode_free(body_node_p); 189 | xmlnode_free(carbons_node_p); 190 | 191 | g_free(body_data); 192 | g_free(buddy_name_bare); 193 | } 194 | 195 | void carbons_enable_cb(JabberStream * js_p, const char * from, 196 | JabberIqType type, const char * id, 197 | xmlnode * packet_p, gpointer data_p) { 198 | const char * accname = purple_account_get_username(purple_connection_get_account(js_p->gc)); 199 | 200 | if (type == JABBER_IQ_ERROR) { 201 | purple_debug_error(CARBONS_LOG_CATEGORY, "Server returned an error when trying to activate carbons for %s.\n", accname); 202 | } else { 203 | purple_debug_info(CARBONS_LOG_CATEGORY, "Successfully activated carbons for %s.\n", accname); 204 | } 205 | } 206 | 207 | void carbons_discover_cb(JabberStream * js_p, const char * from, 208 | JabberIqType type, const char * id, 209 | xmlnode * packet_p, gpointer data_p) { 210 | xmlnode * query_node_p = (void *) 0; 211 | xmlnode * child_node_p = (void *) 0; 212 | JabberIq * jiq_p = (void *) 0; 213 | xmlnode * req_node_p = (void *) 0; 214 | 215 | const char * feature_name = (void *) 0; 216 | const char * accname = purple_account_get_username(purple_connection_get_account(js_p->gc)); 217 | 218 | if (type == JABBER_IQ_ERROR) { 219 | purple_debug_error(CARBONS_LOG_CATEGORY, "Server returned an error when trying to discover carbons for %s.\n", accname); 220 | return; 221 | } 222 | 223 | query_node_p = xmlnode_get_child_with_namespace(packet_p, "query", DISCO_XMLNS); 224 | if (!query_node_p) { 225 | purple_debug_error(CARBONS_LOG_CATEGORY, "No 'query' node in feature discovery reply for %s.\n", accname); 226 | return; 227 | } 228 | 229 | for (child_node_p = query_node_p->child; child_node_p; child_node_p = child_node_p->next) { 230 | if (g_strcmp0(child_node_p->name, "feature")) { 231 | continue; 232 | } 233 | 234 | feature_name = xmlnode_get_attrib(child_node_p, "var"); 235 | if (!g_strcmp0(CARBONS_XMLNS, feature_name)) { 236 | purple_debug_info(CARBONS_LOG_CATEGORY, "Found carbons in server features, sending enable request for %s.\n", accname); 237 | 238 | jiq_p = jabber_iq_new(js_p, JABBER_IQ_SET); 239 | req_node_p = xmlnode_new_child(jiq_p->node, "enable"); 240 | xmlnode_set_namespace(req_node_p, CARBONS_XMLNS); 241 | 242 | jabber_iq_set_callback(jiq_p, carbons_enable_cb, (void *) 0); 243 | jabber_iq_send(jiq_p); 244 | 245 | purple_debug_info(CARBONS_LOG_CATEGORY, "Sent enable request for %s.\n", accname); 246 | return; 247 | } 248 | } 249 | 250 | purple_debug_info(CARBONS_LOG_CATEGORY, "Server does not support message carbons, therefore doing nothing for %s.\n", accname); 251 | } 252 | 253 | void carbons_account_connect_cb(PurpleAccount * acc_p) { 254 | if (strcmp(purple_account_get_protocol_id(acc_p), JABBER_PROTOCOL_ID)) { 255 | return; 256 | } 257 | 258 | // "migration code" - remove obsolete setting 259 | purple_account_remove_setting(acc_p, CARBONS_SETTING_NAME); 260 | 261 | // send discovery request 262 | JabberIq * jiq_p = (void *) 0; 263 | xmlnode * query_node_p = (void *) 0; 264 | JabberStream * js_p = purple_connection_get_protocol_data(purple_account_get_connection(acc_p)); 265 | jiq_p = jabber_iq_new(js_p, JABBER_IQ_GET); 266 | xmlnode_set_attrib(jiq_p->node, "to", js_p->user->domain); 267 | query_node_p = xmlnode_new_child(jiq_p->node, "query"); 268 | xmlnode_set_namespace(query_node_p, DISCO_XMLNS); 269 | 270 | jabber_iq_set_callback(jiq_p, carbons_discover_cb, (void *) 0); 271 | jabber_iq_send(jiq_p); 272 | 273 | purple_debug_info(CARBONS_LOG_CATEGORY, "Sent feature discovery request for %s.\n", purple_account_get_username(acc_p)); 274 | } 275 | 276 | gboolean 277 | carbons_plugin_load(PurplePlugin * plugin_p) { 278 | 279 | GList * accs_l_p = (void *) 0; 280 | GList * curr_p = (void *) 0; 281 | PurpleAccount * acc_p = (void *) 0; 282 | int some_acc_is_connected = 0; 283 | 284 | // manually call init code if there are already accounts connected, e.g. when plugin is loaded manually 285 | accs_l_p = purple_accounts_get_all_active(); 286 | for (curr_p = accs_l_p; curr_p; curr_p = curr_p->next) { 287 | acc_p = (PurpleAccount *) curr_p->data; 288 | if (purple_account_is_connected(acc_p)) { 289 | some_acc_is_connected = 1; 290 | carbons_account_connect_cb(acc_p); 291 | } 292 | } 293 | 294 | if(!some_acc_is_connected) { 295 | // according to the docs, Bad Things(TM) will happen if this is called while accounts are connected 296 | (void) jabber_add_feature(CARBONS_XMLNS, (void *) 0); 297 | } 298 | 299 | (void) purple_signal_connect(purple_accounts_get_handle(), "account-signed-on", plugin_p, PURPLE_CALLBACK(carbons_account_connect_cb), NULL); 300 | (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); 301 | (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); 302 | 303 | g_list_free(accs_l_p); 304 | 305 | return TRUE; 306 | } 307 | 308 | static PurplePluginInfo info = { 309 | PURPLE_PLUGIN_MAGIC, 310 | PURPLE_MAJOR_VERSION, 311 | PURPLE_MINOR_VERSION, 312 | PURPLE_PLUGIN_STANDARD, 313 | NULL, 314 | 0, 315 | NULL, 316 | PURPLE_PRIORITY_DEFAULT, 317 | 318 | "core-riba-carbons", 319 | "XMPP Message Carbons", 320 | CARBONS_VERSION, 321 | 322 | "Implements XEP-0280: Message Carbons as a plugin.", 323 | "This plugin enables a consistent history view across multiple devices which are online at the same time.", 324 | CARBONS_AUTHOR, 325 | "https://github.com/gkdr/carbons", 326 | 327 | carbons_plugin_load, 328 | NULL, 329 | NULL, 330 | 331 | NULL, 332 | NULL, 333 | NULL, 334 | NULL, 335 | NULL, 336 | NULL, 337 | NULL, 338 | NULL 339 | }; 340 | 341 | static void 342 | carbons_plugin_init(PurplePlugin * plugin_p) 343 | { 344 | PurplePluginInfo * info_p = plugin_p->info; 345 | 346 | info_p->dependencies = g_list_prepend(info_p->dependencies, JABBER_PROTOCOL_ID); 347 | } 348 | 349 | PURPLE_INIT_PLUGIN(carbons, carbons_plugin_init, info) 350 | -------------------------------------------------------------------------------- /src/carbons.h: -------------------------------------------------------------------------------- 1 | #ifndef __CARBONS_H 2 | # define __CARBONS_H 3 | 4 | # define CARBONS_VERSION "0.2.3" 5 | # define CARBONS_AUTHOR "Richard Bayerle " 6 | 7 | #endif /* __CARBONS_H */ 8 | -------------------------------------------------------------------------------- /src/carbons_internal.h: -------------------------------------------------------------------------------- 1 | #ifndef __CARBONS_INT_H 2 | # define __CARBONS_INT_H 3 | 4 | void carbons_xml_received_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp); 5 | void carbons_xml_stripped_cb(PurpleConnection * gc_p, xmlnode ** stanza_pp); 6 | void carbons_discover(PurpleAccount * acc_p); 7 | void carbons_discover_cb(JabberStream * js_p, const char * from, 8 | JabberIqType type, const char * id, 9 | xmlnode * packet_p, gpointer data_p); 10 | void carbons_enable_cb(JabberStream * js_p, const char * from, 11 | JabberIqType type, const char * id, 12 | xmlnode * packet_p, gpointer data_p); 13 | 14 | void carbons_account_connect_cb(PurpleAccount * acc_p); 15 | gboolean carbons_plugin_load(PurplePlugin * plugin_p); 16 | 17 | #endif /* CARBONS_INTERNAL_H */ 18 | -------------------------------------------------------------------------------- /test/mocks.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "jabber.h" 7 | 8 | #define CARBONS_XMLNS "urn:xmpp:carbons:2" 9 | #define DISCO_XMLNS "http://jabber.org/protocol/disco#info" 10 | 11 | gboolean __wrap_purple_account_is_connected(const PurpleAccount * acc_p) { 12 | gboolean connected; 13 | connected = mock_type(gboolean); 14 | return connected; 15 | } 16 | 17 | const char * __wrap_purple_account_get_protocol_id(const PurpleAccount * acc_p) { 18 | check_expected_ptr(acc_p); 19 | 20 | char * protocol_id; 21 | protocol_id = mock_ptr_type(char *); 22 | return protocol_id; 23 | } 24 | 25 | char * __wrap_purple_account_get_username(PurpleAccount * acc_p) { 26 | char * username; 27 | 28 | username = mock_ptr_type(char *); 29 | 30 | return username; 31 | } 32 | 33 | PurpleConnection * __wrap_purple_account_get_connection(PurpleAccount * acc_p) { 34 | PurpleConnection * connection_p; 35 | 36 | connection_p = mock_ptr_type(PurpleConnection *); 37 | 38 | return connection_p; 39 | } 40 | 41 | PurpleAccount * __wrap_purple_connection_get_account(const PurpleConnection * gc_p) { 42 | PurpleAccount * account_p; 43 | 44 | account_p = mock_ptr_type(PurpleAccount *); 45 | 46 | return account_p; 47 | } 48 | 49 | void * __wrap_purple_connection_get_protocol_data(const PurpleConnection * connection_p) { 50 | JabberStream * js_p; 51 | 52 | js_p = mock_ptr_type(JabberStream *); 53 | 54 | return js_p; 55 | } 56 | 57 | void __wrap_jabber_iq_send(JabberIq * iq_p) { 58 | check_expected(iq_p->type); 59 | check_expected(iq_p->callback); 60 | 61 | const char * to = xmlnode_get_attrib(iq_p->node, "to"); 62 | check_expected(to); 63 | 64 | xmlnode * query_node_p = xmlnode_get_child_with_namespace(iq_p->node, "query", DISCO_XMLNS); 65 | check_expected(query_node_p); 66 | 67 | xmlnode * enable_node_p = xmlnode_get_child_with_namespace(iq_p->node, "enable", CARBONS_XMLNS); 68 | check_expected(enable_node_p); 69 | } 70 | 71 | void __wrap_purple_debug_error(const char * category, const char * format, ...) { 72 | function_called(); 73 | } 74 | 75 | void __wrap_purple_debug_warning(const char * category, const char * format, ...) { 76 | function_called(); 77 | } 78 | 79 | PurpleConversation * __wrap_purple_find_conversation_with_account(PurpleConversationType type, const char * name, const PurpleAccount *account) { 80 | PurpleConversation * pc_p; 81 | 82 | pc_p = mock_ptr_type(PurpleConversation *); 83 | 84 | return pc_p; 85 | } 86 | 87 | void __wrap_purple_conversation_write(PurpleConversation * conv_p, const char * who, 88 | const char * message, PurpleMessageFlags flags, time_t mtime) { 89 | check_expected_ptr(conv_p); 90 | check_expected(who); 91 | check_expected(message); 92 | check_expected(flags); 93 | } 94 | 95 | PurpleConversation * __wrap_purple_conversation_new(PurpleConversationType type, 96 | PurpleAccount * account, 97 | const char * name) { 98 | check_expected(type); 99 | check_expected_ptr(account); 100 | check_expected(name); 101 | 102 | PurpleConversation * conv_p; 103 | conv_p = mock_ptr_type(PurpleConversation *); 104 | return conv_p; 105 | } 106 | 107 | void __wrap_jabber_add_feature(const gchar * namespace, JabberFeatureEnabled cb) { 108 | check_expected(namespace); 109 | } 110 | 111 | void * __wrap_purple_accounts_get_handle(void) { 112 | void * handle_p; 113 | handle_p = mock_ptr_type(void *); 114 | return handle_p; 115 | } 116 | 117 | PurplePlugin * __wrap_purple_plugins_find_with_id(const char * id) { 118 | check_expected(id); 119 | 120 | PurplePlugin * plugin_p; 121 | plugin_p = mock_ptr_type(PurplePlugin *); 122 | return plugin_p; 123 | } 124 | 125 | gulong __wrap_purple_signal_connect(void * instance, 126 | const char * signal, 127 | void * handle, 128 | PurpleCallback func, 129 | void * data) { 130 | check_expected_ptr(instance); 131 | check_expected(signal); 132 | check_expected_ptr(handle); 133 | check_expected_ptr(func); 134 | 135 | return 1; // ignored 136 | } 137 | 138 | gulong __wrap_purple_signal_connect_priority(void * instance, 139 | const char * signal, 140 | void * handle, 141 | PurpleCallback func, 142 | void * data, 143 | int priority) { 144 | check_expected_ptr(instance); 145 | check_expected(signal); 146 | check_expected_ptr(handle); 147 | check_expected_ptr(func); 148 | check_expected(priority); 149 | 150 | return 2; // ignored 151 | } 152 | 153 | GList * __wrap_purple_accounts_get_all_active(void) { 154 | GList * active_accounts; 155 | active_accounts = mock_ptr_type(GList *); 156 | return active_accounts; 157 | } -------------------------------------------------------------------------------- /test/test_carbons.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "jabber.h" 7 | 8 | #include "../src/carbons.h" 9 | #include "../src/carbons_internal.h" 10 | #include "mocks.c" 11 | 12 | /** 13 | * Shuould send well-formed "enable" request if feature is contained in discovery response. 14 | */ 15 | static void test_carbons_discover_cb_success(void ** state) { 16 | (void) state; 17 | 18 | const char * test_jid = "romeo@montague.example/garden"; 19 | 20 | // example from docs 21 | const char * reply = "" 23 | "" 24 | "" 25 | "" 26 | ""; 27 | xmlnode * reply_node_p = xmlnode_from_str(reply, -1); 28 | 29 | JabberStream * js_p = malloc(sizeof (JabberStream)); 30 | js_p->next_id = 1; 31 | js_p->user = jabber_id_new(test_jid); 32 | 33 | will_return(__wrap_purple_connection_get_account, NULL); 34 | will_return(__wrap_purple_account_get_username, test_jid); 35 | 36 | expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); 37 | expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); 38 | expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); 39 | 40 | // not set here 41 | expect_value(__wrap_jabber_iq_send, to, NULL); 42 | expect_value(__wrap_jabber_iq_send, query_node_p, NULL); 43 | 44 | carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); 45 | 46 | free(js_p); 47 | } 48 | 49 | /** 50 | * Success case with a real world example (reply received from Prosody 0.11.0). 51 | */ 52 | static void test_carbons_discover_cb_real_world_reply(void ** state) { 53 | (void) state; 54 | 55 | const char * own_jid = "b@localhost/pidgin"; 56 | const char * reply = "" 57 | "" 58 | "" 59 | "" 60 | "" 61 | "" 62 | "" 63 | "" 64 | "" 65 | "" 66 | "" 67 | "" 68 | "" 69 | "" 70 | "" 71 | "" 72 | "" 73 | "" 74 | "" 75 | "" 76 | "" 77 | ""; 78 | xmlnode * reply_node_p = xmlnode_from_str(reply, -1); 79 | 80 | JabberStream * js_p = malloc(sizeof (JabberStream)); 81 | js_p->next_id = 1; 82 | js_p->user = jabber_id_new(own_jid); 83 | 84 | will_return(__wrap_purple_connection_get_account, NULL); 85 | will_return(__wrap_purple_account_get_username, own_jid); 86 | 87 | expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); 88 | expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); 89 | expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); 90 | 91 | // not set here 92 | expect_value(__wrap_jabber_iq_send, to, NULL); 93 | expect_value(__wrap_jabber_iq_send, query_node_p, NULL); 94 | 95 | carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); 96 | 97 | free(js_p); 98 | } 99 | 100 | /** 101 | * Positive reply and the feature is the first child of the query node. 102 | */ 103 | static void test_carbons_discover_cb_first_child(void ** state) { 104 | (void) state; 105 | 106 | const char * own_jid = "b@localhost/pidgin"; 107 | const char * reply = "" 108 | "" 109 | "" 110 | "" 111 | "" 112 | "" 113 | "" 114 | "" 115 | "" 116 | "" 117 | "" 118 | "" 119 | "" 120 | "" 121 | "" 122 | "" 123 | "" 124 | "" 125 | "" 126 | "" 127 | "" 128 | ""; 129 | xmlnode * reply_node_p = xmlnode_from_str(reply, -1); 130 | 131 | JabberStream * js_p = malloc(sizeof (JabberStream)); 132 | js_p->next_id = 1; 133 | js_p->user = jabber_id_new(own_jid); 134 | 135 | will_return(__wrap_purple_connection_get_account, NULL); 136 | will_return(__wrap_purple_account_get_username, own_jid); 137 | 138 | expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); 139 | expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); 140 | expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); 141 | 142 | // not set here 143 | expect_value(__wrap_jabber_iq_send, to, NULL); 144 | expect_value(__wrap_jabber_iq_send, query_node_p, NULL); 145 | 146 | carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); 147 | 148 | free(js_p); 149 | } 150 | 151 | /** 152 | * Positive reply and the feature is the last cild of the query node. 153 | */ 154 | static void test_carbons_discover_cb_last_child(void ** state) { 155 | (void) state; 156 | 157 | const char * own_jid = "b@localhost/pidgin"; 158 | const char * reply = "" 159 | "" 160 | "" 161 | "" 162 | "" 163 | "" 164 | "" 165 | "" 166 | "" 167 | "" 168 | "" 169 | "" 170 | "" 171 | "" 172 | "" 173 | "" 174 | "" 175 | "" 176 | "" 177 | "" 178 | "" 179 | ""; 180 | xmlnode * reply_node_p = xmlnode_from_str(reply, -1); 181 | 182 | JabberStream * js_p = malloc(sizeof (JabberStream)); 183 | js_p->next_id = 1; 184 | js_p->user = jabber_id_new(own_jid); 185 | 186 | will_return(__wrap_purple_connection_get_account, NULL); 187 | will_return(__wrap_purple_account_get_username, own_jid); 188 | 189 | expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_SET); 190 | expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_enable_cb); 191 | expect_not_value(__wrap_jabber_iq_send, enable_node_p, NULL); 192 | 193 | // not set here 194 | expect_value(__wrap_jabber_iq_send, to, NULL); 195 | expect_value(__wrap_jabber_iq_send, query_node_p, NULL); 196 | 197 | carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); 198 | 199 | free(js_p); 200 | } 201 | 202 | /** 203 | * Query successful, but carbons is not contained in the reply. 204 | */ 205 | static void test_carbons_discover_cb_no_carbons(void ** state) { 206 | (void) state; 207 | 208 | const char * own_jid = "b@localhost/pidgin"; 209 | const char * reply = "" 210 | "" 211 | "" 212 | "" 213 | "" 214 | "" 215 | "" 216 | "" 217 | "" 218 | "" 219 | "" 220 | "" 221 | "" 222 | "" 223 | "" 224 | "" 225 | "" 226 | "" 227 | "" 228 | "" 229 | ""; 230 | xmlnode * reply_node_p = xmlnode_from_str(reply, -1); 231 | 232 | JabberStream * js_p = malloc(sizeof (JabberStream)); 233 | will_return(__wrap_purple_connection_get_account, NULL); 234 | will_return(__wrap_purple_account_get_username, own_jid); 235 | 236 | // for now, no idea how to check for "not called", so at least make sure it doesn't crash in this case 237 | 238 | carbons_discover_cb(js_p, "from", JABBER_IQ_RESULT, "id", reply_node_p, NULL); 239 | 240 | free(js_p); 241 | } 242 | 243 | /** 244 | * Should abort when receiving an error reply. 245 | */ 246 | static void test_carbons_discover_cb_error(void ** state) { 247 | (void) state; 248 | 249 | const char * test_jid = "romeo@montague.example/garden"; 250 | 251 | JabberStream * js_p = malloc(sizeof (JabberStream)); 252 | 253 | will_return(__wrap_purple_connection_get_account, NULL); 254 | will_return(__wrap_purple_account_get_username, test_jid); 255 | 256 | expect_function_call(__wrap_purple_debug_error); 257 | 258 | carbons_discover_cb(js_p, "from", JABBER_IQ_ERROR, "id", NULL, NULL); 259 | 260 | free(js_p); 261 | } 262 | 263 | static void test_carbons_discover_cb_empty_reply(void ** state) { 264 | (void) state; 265 | 266 | const char * own_jid = "romeo@montague.example/garden"; 267 | 268 | const char * reply = "" 270 | ""; 271 | xmlnode * reply_node_p = xmlnode_from_str(reply, -1); 272 | 273 | JabberStream * js_p = malloc(sizeof (JabberStream)); 274 | 275 | will_return(__wrap_purple_connection_get_account, NULL); 276 | will_return(__wrap_purple_account_get_username, own_jid); 277 | 278 | expect_function_call(__wrap_purple_debug_error); 279 | 280 | carbons_discover_cb(js_p, "montague.example", JABBER_IQ_RESULT, "id", reply_node_p, NULL); 281 | 282 | free(js_p); 283 | 284 | } 285 | 286 | /** 287 | * Do nothing (and especially not crash) when the xmlnode ** is null. Some plugins do this. 288 | */ 289 | static void test_carbons_xml_received_cb_nullptr(void ** state) { 290 | (void) state; 291 | 292 | carbons_xml_received_cb(NULL, NULL); 293 | } 294 | 295 | /** 296 | * Do not crash when the given xmlnode * is null. 297 | */ 298 | static void test_carbons_xml_received_cb_null(void ** state) { 299 | (void) state; 300 | 301 | xmlnode * node_p = NULL; 302 | carbons_xml_received_cb(NULL, &node_p); 303 | } 304 | 305 | /** 306 | * Stop processing when the received stanza is not a 'message'. 307 | */ 308 | static void test_carbons_xml_received_cb_no_msg(void ** state) { 309 | (void) state; 310 | 311 | char * stanza = 312 | "" 316 | "Neither, fair saint, if either thee dislike." 317 | "0e3141cd80894871a68e6fe6b1ec56fa" 318 | ""; 319 | xmlnode * iq_node_p = xmlnode_from_str(stanza, -1); 320 | 321 | carbons_xml_received_cb(NULL, &iq_node_p); 322 | 323 | xmlnode * body_node_p = xmlnode_get_child(iq_node_p, "body"); 324 | assert_string_equal("Neither, fair saint, if either thee dislike.", xmlnode_get_data(body_node_p)); 325 | } 326 | 327 | /** 328 | * 'Reject' carbons messages sent by someone other than the own, bare JID. 329 | * Removes the inner carbons node since it's a malicious message. 330 | */ 331 | static void test_carbons_xml_received_cb_invalid_sender_received(void ** state) { 332 | (void) state; 333 | 334 | const char * received_carbon_copy = 335 | "" 339 | "" 340 | "" 341 | "" 345 | "What man art thou that, thus bescreen'd in night, so stumblest on my counsel?" 346 | "0e3141cd80894871a68e6fe6b1ec56fa" 347 | "" 348 | "" 349 | "" 350 | ""; 351 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 352 | 353 | will_return(__wrap_purple_connection_get_account, NULL); 354 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 355 | 356 | expect_function_calls(__wrap_purple_debug_warning, 2); 357 | 358 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 359 | 360 | assert_non_null(received_carbons_node_p); 361 | assert_null(xmlnode_get_child(received_carbons_node_p, "received")); 362 | } 363 | 364 | /** 365 | * Same as above, but for a carbon copy of a sent message. 366 | */ 367 | static void test_carbons_xml_received_cb_invalid_sender_sent(void ** state) { 368 | (void) state; 369 | 370 | const char * received_carbon_copy = 371 | "" 375 | "" 376 | "" 377 | "" 381 | "Neither, fair saint, if either thee dislike." 382 | "0e3141cd80894871a68e6fe6b1ec56fa" 383 | "" 384 | "" 385 | "" 386 | ""; 387 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 388 | 389 | will_return(__wrap_purple_connection_get_account, NULL); 390 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 391 | 392 | expect_function_calls(__wrap_purple_debug_warning, 2); 393 | 394 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 395 | 396 | assert_non_null(received_carbons_node_p); 397 | assert_null(xmlnode_get_child(received_carbons_node_p, "sent")); 398 | } 399 | 400 | /** 401 | * Default case for a received carbon copy of a received message: 402 | * Strip outer message and give libpurple the inner one. 403 | */ 404 | static void test_carbons_xml_received_cb_received_success(void ** state) { 405 | (void) state; 406 | 407 | const char * received_carbon_copy = 408 | "" 412 | "" 413 | "" 414 | "" 418 | "What man art thou that, thus bescreen'd in night, so stumblest on my counsel?" 419 | "0e3141cd80894871a68e6fe6b1ec56fa" 420 | "" 421 | "" 422 | "" 423 | ""; 424 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 425 | 426 | will_return(__wrap_purple_connection_get_account, NULL); 427 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 428 | 429 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 430 | 431 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "juliet@capulet.example/balcony"); 432 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/garden"); 433 | assert_ptr_not_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); 434 | } 435 | 436 | /** 437 | * Stop processing on malformed carbon-copy of received message: no 'forwarded' node. 438 | */ 439 | static void test_carbons_xml_received_cb_received_no_forwarded(void ** state) { 440 | (void) state; 441 | 442 | const char * received_carbon_copy = 443 | "" 447 | "" 448 | "" 452 | "What man art thou that, thus bescreen'd in night, so stumblest on my counsel?" 453 | "0e3141cd80894871a68e6fe6b1ec56fa" 454 | "" 455 | "" 456 | ""; 457 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 458 | 459 | will_return(__wrap_purple_connection_get_account, NULL); 460 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 461 | 462 | expect_function_call(__wrap_purple_debug_error); 463 | 464 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 465 | 466 | // no change since there was no processing 467 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); 468 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/home"); 469 | assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); 470 | } 471 | 472 | /** 473 | * Stop processing on malformed carbon-copy of received message: no 'message' node. 474 | */ 475 | static void test_carbons_xml_received_cb_received_no_message(void ** state) { 476 | (void) state; 477 | 478 | const char * received_carbon_copy = 479 | "" 483 | "" 484 | "" 485 | "" 486 | ""; 487 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 488 | 489 | will_return(__wrap_purple_connection_get_account, NULL); 490 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 491 | 492 | expect_function_call(__wrap_purple_debug_error); 493 | 494 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 495 | 496 | // no change since there was no processing 497 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); 498 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/home"); 499 | assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); 500 | } 501 | 502 | /** 503 | * Default case for a received carbon copy of a sent message: 504 | * Strip the outer message and give libpurple the inner one, 505 | * plus inject another '' node for detection by second, later callback. 506 | */ 507 | static void test_carbons_xml_received_cb_sent_success(void ** state) { 508 | (void) state; 509 | 510 | const char * received_carbon_copy = 511 | "" 515 | "" 516 | "" 517 | "" 521 | "Neither, fair saint, if either thee dislike." 522 | "0e3141cd80894871a68e6fe6b1ec56fa" 523 | "" 524 | "" 525 | "" 526 | ""; 527 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 528 | 529 | will_return(__wrap_purple_connection_get_account, NULL); 530 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 531 | 532 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 533 | 534 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example/home"); 535 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "juliet@capulet.example/balcony"); 536 | assert_ptr_not_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); 537 | assert_ptr_not_equal(xmlnode_get_child_with_namespace(received_carbons_node_p, "sent", CARBONS_XMLNS), NULL); 538 | } 539 | 540 | /** 541 | * Stop processing on malformed carbon-copy of sent message: no 'forwaded' node. 542 | */ 543 | static void test_carbons_xml_received_cb_sent_no_forwarded(void ** state) { 544 | (void) state; 545 | 546 | const char * received_carbon_copy = 547 | "" 551 | "" 552 | "" 556 | "Neither, fair saint, if either thee dislike." 557 | "0e3141cd80894871a68e6fe6b1ec56fa" 558 | "" 559 | "" 560 | ""; 561 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 562 | 563 | will_return(__wrap_purple_connection_get_account, NULL); 564 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 565 | 566 | expect_function_call(__wrap_purple_debug_error); 567 | 568 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 569 | 570 | // no change since there was no processing 571 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); 572 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/garden"); 573 | assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); 574 | } 575 | 576 | /** 577 | * Stop processing on malformed carbon-copy of sent message: no 'message' node. 578 | */ 579 | static void test_carbons_xml_received_cb_sent_no_message(void ** state) { 580 | (void) state; 581 | 582 | const char * received_carbon_copy = 583 | "" 587 | "" 588 | "" 589 | "" 590 | ""; 591 | xmlnode * received_carbons_node_p = xmlnode_from_str(received_carbon_copy, -1); 592 | 593 | will_return(__wrap_purple_connection_get_account, NULL); 594 | will_return(__wrap_purple_account_get_username, "romeo@montague.example"); 595 | 596 | expect_function_call(__wrap_purple_debug_error); 597 | 598 | carbons_xml_received_cb(NULL, &received_carbons_node_p); 599 | 600 | // no change since there was no processing 601 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "from"), "romeo@montague.example"); 602 | assert_string_equal(xmlnode_get_attrib(received_carbons_node_p, "to"), "romeo@montague.example/garden"); 603 | assert_ptr_equal(xmlnode_get_child(received_carbons_node_p, "body"), NULL); 604 | } 605 | 606 | static void test_carbons_xml_stripped_cb_nullptr(void ** state) { 607 | (void) state; 608 | 609 | carbons_xml_stripped_cb(NULL, NULL); 610 | } 611 | 612 | static void test_carbons_xml_stripped_cb_null(void ** state) { 613 | (void) state; 614 | 615 | xmlnode * node_p = NULL; 616 | carbons_xml_stripped_cb(NULL, &node_p); 617 | } 618 | 619 | /** 620 | * If the stanza contains an empty 'sent' node injected by the earlier callback, write the body to the conversation. 621 | */ 622 | static void test_carbons_xml_stripped_cb_success(void ** state) { 623 | (void) state; 624 | 625 | const char * stripped_carbon_copy = 626 | "" 630 | "" 631 | "Neither, fair saint, if either thee dislike." 632 | "0e3141cd80894871a68e6fe6b1ec56fa" 633 | ""; 634 | xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); 635 | 636 | will_return(__wrap_purple_connection_get_account, NULL); 637 | PurpleConversation * pc_p = NULL; 638 | will_return(__wrap_purple_find_conversation_with_account, &pc_p); 639 | 640 | expect_value(__wrap_purple_conversation_write, conv_p, &pc_p); 641 | expect_string(__wrap_purple_conversation_write, who, "romeo@montague.example/home"); 642 | expect_string(__wrap_purple_conversation_write, message, "Neither, fair saint, if either thee dislike."); 643 | expect_value(__wrap_purple_conversation_write, flags, PURPLE_MESSAGE_SEND); 644 | 645 | carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); 646 | 647 | assert_non_null(stripped_carbons_node_p); 648 | assert_null(xmlnode_get_child(stripped_carbons_node_p, "sent")); 649 | assert_null(xmlnode_get_child(stripped_carbons_node_p, "body")); 650 | } 651 | 652 | /** 653 | * Like above, but also create the conversation window if it does not exist yet. 654 | */ 655 | static void test_carbons_xml_stripped_cb_success_new_conv(void ** state) { 656 | (void) state; 657 | 658 | const char * stripped_carbon_copy = 659 | "" 663 | "" 664 | "Neither, fair saint, if either thee dislike." 665 | "0e3141cd80894871a68e6fe6b1ec56fa" 666 | ""; 667 | xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); 668 | 669 | char * acc_mock = "fake purple account"; 670 | will_return(__wrap_purple_connection_get_account, &acc_mock); 671 | will_return(__wrap_purple_find_conversation_with_account, NULL); 672 | 673 | expect_value(__wrap_purple_conversation_new, type, PURPLE_CONV_TYPE_IM); 674 | expect_value(__wrap_purple_conversation_new, account, &acc_mock); 675 | expect_string(__wrap_purple_conversation_new, name, "juliet@capulet.example"); 676 | 677 | PurpleConversation * pc_p = NULL; 678 | will_return(__wrap_purple_conversation_new, &pc_p); 679 | 680 | expect_value(__wrap_purple_conversation_write, conv_p, &pc_p); 681 | expect_string(__wrap_purple_conversation_write, who, "romeo@montague.example/home"); 682 | expect_string(__wrap_purple_conversation_write, message, "Neither, fair saint, if either thee dislike."); 683 | expect_value(__wrap_purple_conversation_write, flags, PURPLE_MESSAGE_SEND); 684 | 685 | carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); 686 | 687 | assert_non_null(stripped_carbons_node_p); 688 | assert_null(xmlnode_get_child(stripped_carbons_node_p, "sent")); 689 | assert_null(xmlnode_get_child(stripped_carbons_node_p, "body")); 690 | } 691 | 692 | /** 693 | * Do nothing if the stanza is not a 'message'. 694 | */ 695 | static void test_carbons_xml_stripped_cb_not_a_message(void ** state) { 696 | (void) state; 697 | 698 | const char * stripped_carbon_copy = 699 | "" 703 | "Neither, fair saint, if either thee dislike." 704 | "0e3141cd80894871a68e6fe6b1ec56fa" 705 | ""; 706 | xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); 707 | 708 | carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); 709 | 710 | assert_string_equal(xmlnode_to_str(stripped_carbons_node_p, NULL), stripped_carbon_copy); 711 | } 712 | 713 | /** 714 | * Do nothing if the stanza does not contain an empty 'sent' node. 715 | */ 716 | static void test_carbons_xml_stripped_cb_do_nothing(void ** state) { 717 | (void) state; 718 | 719 | const char * stripped_carbon_copy = 720 | "" 724 | "Neither, fair saint, if either thee dislike." 725 | "0e3141cd80894871a68e6fe6b1ec56fa" 726 | ""; 727 | xmlnode * stripped_carbons_node_p = xmlnode_from_str(stripped_carbon_copy, -1); 728 | 729 | carbons_xml_stripped_cb(NULL, &stripped_carbons_node_p); 730 | 731 | assert_string_equal(xmlnode_to_str(stripped_carbons_node_p, NULL), stripped_carbon_copy); 732 | } 733 | 734 | /** 735 | * Add carbons to client capabilities, register the init callback for accounts signing on, 736 | * and also the two message handling callbacks on incoming XML. 737 | */ 738 | static void test_carbons_plugin_load_app_start(void ** state) { 739 | (void) state; 740 | 741 | void * plugin_mock = "plugin mock"; 742 | 743 | void * accounts_handle_mock = "accounts handle mock"; 744 | will_return(__wrap_purple_accounts_get_handle, accounts_handle_mock); 745 | expect_value(__wrap_purple_signal_connect, instance, accounts_handle_mock); 746 | expect_string(__wrap_purple_signal_connect, signal, "account-signed-on"); 747 | expect_value(__wrap_purple_signal_connect, handle, plugin_mock); 748 | expect_value(__wrap_purple_signal_connect, func, carbons_account_connect_cb); 749 | 750 | void * jabber_handle_mock = "jabber handle mock"; 751 | expect_string_count(__wrap_purple_plugins_find_with_id, id, "prpl-jabber", 2); 752 | will_return_count(__wrap_purple_plugins_find_with_id, jabber_handle_mock, 2); 753 | 754 | expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); 755 | expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); 756 | expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); 757 | expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_received_cb); 758 | expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_LOWEST + 100); 759 | 760 | expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); 761 | expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); 762 | expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); 763 | expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_stripped_cb); 764 | expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_HIGHEST - 50); 765 | 766 | will_return(__wrap_purple_accounts_get_all_active, NULL); 767 | 768 | expect_string(__wrap_jabber_add_feature, namespace, CARBONS_XMLNS); 769 | 770 | assert_true(carbons_plugin_load(plugin_mock)); 771 | } 772 | 773 | /** 774 | * If the plugin is loaded while the application is already running, the functions which are usually called on 775 | * account connect have to be called manually. 776 | */ 777 | static void test_carbons_plugin_load_while_connected(void ** state) { 778 | (void) state; 779 | 780 | void * plugin_mock = "plugin mock"; 781 | 782 | void * accounts_handle_mock = "accounts handle mock"; 783 | will_return(__wrap_purple_accounts_get_handle, accounts_handle_mock); 784 | expect_value(__wrap_purple_signal_connect, instance, accounts_handle_mock); 785 | expect_string(__wrap_purple_signal_connect, signal, "account-signed-on"); 786 | expect_value(__wrap_purple_signal_connect, handle, plugin_mock); 787 | expect_value(__wrap_purple_signal_connect, func, carbons_account_connect_cb); 788 | 789 | void * jabber_handle_mock = "jabber handle mock"; 790 | expect_string_count(__wrap_purple_plugins_find_with_id, id, "prpl-jabber", 2); 791 | will_return_count(__wrap_purple_plugins_find_with_id, jabber_handle_mock, 2); 792 | 793 | expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); 794 | expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); 795 | expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); 796 | expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_received_cb); 797 | expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_LOWEST + 100); 798 | 799 | expect_value(__wrap_purple_signal_connect_priority, instance, jabber_handle_mock); 800 | expect_string(__wrap_purple_signal_connect_priority, signal, "jabber-receiving-xmlnode"); 801 | expect_value(__wrap_purple_signal_connect_priority, handle, plugin_mock); 802 | expect_value(__wrap_purple_signal_connect_priority, func, carbons_xml_stripped_cb); 803 | expect_value(__wrap_purple_signal_connect_priority, priority, PURPLE_PRIORITY_HIGHEST - 50); 804 | 805 | PurpleAccount * account_p = malloc(sizeof(PurpleAccount)); 806 | will_return(__wrap_purple_accounts_get_all_active, g_list_prepend(NULL, account_p)); 807 | will_return(__wrap_purple_account_is_connected, TRUE); 808 | 809 | expect_value(__wrap_purple_account_get_protocol_id, acc_p, account_p); 810 | will_return(__wrap_purple_account_get_protocol_id, "does not matter, just checking if function is called"); 811 | 812 | // unfortunately, there is currently no way to check that jabber_add_feature was NOT called 813 | 814 | assert_true(carbons_plugin_load(plugin_mock)); 815 | 816 | free(account_p); 817 | } 818 | 819 | /** 820 | * Send a discovery request on account connect, but only if the connecting account is of type XMPP- 821 | */ 822 | static void test_carbons_account_connect_cb(void ** state) { 823 | (void) state; 824 | 825 | const char * test_domain = "test.org"; 826 | const char * test_jid = "me-testing@test.org/resource"; 827 | 828 | will_return(__wrap_purple_account_get_protocol_id, "prpl-jabber"); 829 | expect_any(__wrap_purple_account_get_protocol_id, acc_p); 830 | will_return(__wrap_purple_account_get_connection, NULL); 831 | 832 | JabberStream * js_p = malloc(sizeof (JabberStream)); 833 | js_p->next_id = 1; 834 | js_p->user = jabber_id_new(test_jid); 835 | will_return(__wrap_purple_connection_get_protocol_data, js_p); 836 | 837 | will_return(__wrap_purple_account_get_username, test_jid); 838 | 839 | expect_value(__wrap_jabber_iq_send, iq_p->type, JABBER_IQ_GET); 840 | expect_value(__wrap_jabber_iq_send, iq_p->callback, carbons_discover_cb); 841 | expect_string(__wrap_jabber_iq_send, to, test_domain); 842 | expect_not_value(__wrap_jabber_iq_send, query_node_p, NULL); 843 | 844 | // not set here 845 | expect_value(__wrap_jabber_iq_send, enable_node_p, NULL); 846 | 847 | carbons_account_connect_cb(NULL); 848 | 849 | free(js_p); 850 | } 851 | 852 | /** 853 | * Notify user of an error if enabling carbons fails. 854 | */ 855 | static void test_carbons_enable_cb_error(void ** state) { 856 | (void) state; 857 | 858 | will_return(__wrap_purple_connection_get_account, "does not matter"); 859 | will_return(__wrap_purple_account_get_username, "does not matter"); 860 | 861 | expect_function_call(__wrap_purple_debug_error); 862 | 863 | JabberStream * js_p = malloc(sizeof (JabberStream)); 864 | carbons_enable_cb(js_p, "", JABBER_IQ_ERROR, "", NULL, NULL); 865 | 866 | free(js_p); 867 | } 868 | 869 | int main(void) { 870 | const struct CMUnitTest tests[] = { 871 | cmocka_unit_test(test_carbons_discover_cb_success), 872 | cmocka_unit_test(test_carbons_discover_cb_real_world_reply), 873 | cmocka_unit_test(test_carbons_discover_cb_first_child), 874 | cmocka_unit_test(test_carbons_discover_cb_last_child), 875 | cmocka_unit_test(test_carbons_discover_cb_no_carbons), 876 | cmocka_unit_test(test_carbons_discover_cb_error), 877 | cmocka_unit_test(test_carbons_discover_cb_empty_reply), 878 | cmocka_unit_test(test_carbons_xml_received_cb_nullptr), 879 | cmocka_unit_test(test_carbons_xml_received_cb_null), 880 | cmocka_unit_test(test_carbons_xml_received_cb_no_msg), 881 | cmocka_unit_test(test_carbons_xml_received_cb_invalid_sender_received), 882 | cmocka_unit_test(test_carbons_xml_received_cb_invalid_sender_sent), 883 | cmocka_unit_test(test_carbons_xml_received_cb_received_success), 884 | cmocka_unit_test(test_carbons_xml_received_cb_received_no_forwarded), 885 | cmocka_unit_test(test_carbons_xml_received_cb_received_no_message), 886 | cmocka_unit_test(test_carbons_xml_received_cb_sent_success), 887 | cmocka_unit_test(test_carbons_xml_received_cb_sent_no_forwarded), 888 | cmocka_unit_test(test_carbons_xml_received_cb_sent_no_message), 889 | cmocka_unit_test(test_carbons_xml_stripped_cb_nullptr), 890 | cmocka_unit_test(test_carbons_xml_stripped_cb_null), 891 | cmocka_unit_test(test_carbons_xml_stripped_cb_success), 892 | cmocka_unit_test(test_carbons_xml_stripped_cb_success_new_conv), 893 | cmocka_unit_test(test_carbons_xml_stripped_cb_not_a_message), 894 | cmocka_unit_test(test_carbons_xml_stripped_cb_do_nothing), 895 | cmocka_unit_test(test_carbons_plugin_load_app_start), 896 | cmocka_unit_test(test_carbons_plugin_load_while_connected), 897 | cmocka_unit_test(test_carbons_account_connect_cb), 898 | cmocka_unit_test(test_carbons_enable_cb_error) 899 | }; 900 | 901 | return cmocka_run_group_tests(tests, NULL, NULL); 902 | } 903 | --------------------------------------------------------------------------------