config.mk0000644000175000017500000000141612261362415010462 0ustar fsfs# paths PREFIX ?= /usr/local # where are the sources of irssi? IRSSI_INCLUDE ?= ${PREFIX}/include/irssi # where should be installed the module? IRSSI_LIB ?= ${PREFIX}/lib/irssi # where should be installed the documentation? IRSSI_DOC ?= ${PREFIX}/share/doc/irssi # where should be installed the help for commands ? IRSSI_HELP ?= ${PREFIX}/share/irssi/help # includes and libs INCS = ${LIB_INCS} \ -I../../src/core \ -I${IRSSI_INCLUDE} \ -I${IRSSI_INCLUDE}/src \ -I${IRSSI_INCLUDE}/src/core \ -I$(IRSSI_INCLUDE)/src/fe-common/core \ -I$(IRSSI_INCLUDE)/src/fe-text \ `pkg-config --cflags loudmouth-1.0` LIBS = ${LIB_LIBS} # flags CFLAGS += -fPIC -DUOFF_T_LONG LDFLAGS += -shared # debug #CFLAGS += -std=c99 -W -g -Wall -Wno-unused-parameter # compiler and linker CC ?= cc COPYING0000644000175000017500000004310312261357644007726 0ustar fsfs GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. docs/0000755000175000017500000000000012261362415007612 5ustar fsfsdocs/MUC0000644000175000017500000000161512261357644010174 0ustar fsfsMUC commands: ============= /JOIN [/] Join a room. If your nick is not specified, the value of the setting "nick" will be used as your nick in this room. Unlike irssi default behaviour (that you can pass a list of channels separated with a comma), only one room can be passed to this command! /PART [] [] Leaves a room. /QUERY Opens a query window with the nick in the room. /NICK [] Changes your nick in a specific room. /TOPIC [] Changes the topic of the room, if you have the right to do it. /NAME Lists the nicks in the room. /INVITE [/] [] /INVITE [] Invites the specified contact to the current or specified room. Administration commands: ======================== Currently, you cannot manage a room with irssi-xmpp. docs/XEP0000644000175000017500000000077012261357644010205 0ustar fsfsXEPs (XMPP Extension Protocol) support: Fully supported: XEP-0022: Message Events (Superseded by XEP-0085) XEP-0066: Out of Band Data XEP-0077: In-Band Registration XEP-0091: Delayed Delivery (Superseded by XEP-0203) XEP-0092: Software Version XEP-0199: XMPP Ping Partially supported: XEP-0030: Service Discovery XEP-0045: Multi-User Chat (Entity Use Cases and Occupant Use Cases) XEP-0054: vcard-temp XEP-0082: XMPP Date and Time Profiles XEP-0085: Chat State Notifications XEP-0203: Delayed Delivery docs/FAQ0000644000175000017500000000522612261362415010151 0ustar fsfs1. Connection: ============== 1.1 How can I automatically load irssi-xmpp at irssi startup ? Simply put "load xmpp" in your startup file (~/.irssi/startup): echo "load xmpp" >> ~/.irssi/startup 1.2 How can I automatically connect to my account at irssi startup ? You can put these things in your config file (The config file can be found here : "~/.irssi/config"): To create a XMPP network, add to chatnets section: = { type = "XMPP"; nick = ""; }; Then you can add this at the end of the servers section: { address = "
"; port=""; use_ssl = "{yes|no}"; chatnet = ""; password = ""; autoconnect = "{yes|no}"; }; Or in irssi, you can type this: /SERVER ADD -xmppnet
If 0 is specified as port, the default port will be used (5222 for a regular connection or 5223 for SSL). Now you can connect to your jabber account by typing: /CONNECT Or just restart irssi if you have set autoconnect to yes. 1.3 How can I use my gmail/gtalk account ? You have to use the server "talk.google.com", so the command is: /XMPPCONNECT -host talk.google.com You don't need to specify the -ssl switch because STARTTLS will be used automatically. 2. General: =========== 2.1 Why the lagmeter is not working ? The server need to support the XEP-0199 (XMPP Ping). If it doesn't support it, the lagmeter won't work. If your server support the XMPP Ping, maybe you didn't add the composing item in the statusbar. Take a look at the file GENERAL (section "Composing in the statusbar:). 2.2 How can I be away on all servers (both IRC servers and XMPP servers) ? Simply use this command: /foreach server /away -one Or set up an alias like this /alias aaway /foreach server /away -one 3. Scripting: ============= 3.1 How can I use or write scripts with irssi-xmpp ? ... 3.2 My script seems to be incompatible with irssi-xmpp and throws warnings such as: Can't locate object method "xxx" via package "Irssi::Xmpp::Server". How can I get rid of that ? Basically, it's because the script is IRC-specific and won't work with an XMPP server. Try to add a condition in the functions of your script to verify if the server is an IRC server and simply return if it is not. 4. Themes: ========== 4.1 How can I change the theme of the messages of irssi-xmpp ? In the same way you can change the theme of the messages of irssi. Take a look at the source file src/fe-common/module-formats.c to see the whole list of irssi-xmpp messages. docs/GENERAL0000644000175000017500000001516712261357644010634 0ustar fsfsGeneral commands: ================= These commands are the general commands for a basic usage of irssi-xmpp. You may notice that some commands accept as parameter a JID, a full JID (a JID with a resource) or a name. If you specify a name, it will be resolved through the roster. But if the name cannot be found in your roster, irssi-xmpp will assume that the name is a JID. Some commands require a full JID, but if you type only a JID or a name, these commands will automatically use the highest resource for this contact in your roster. /QUERY [/] /QUERY Starts a private conversation with the JID. If the user is online and the resource isn't specified, the conversation window will be on the resource with the highest priority. /MSG [/] Sends a message to a jid. There is no name resolution through the roster so the jid must be valid. (Prefer /QUERY if you want a normal discussion in a query window.) /ME Sends an "ACTION", useable in a query or in a room. /AWAY [away|chat|dnd|xa] This command marks you as being "away". If the away mode isn't specified, the "xmpp_default_away_mode" setting will be used. You can remove your away status by using AWAY with no arguments. /ROSTER Shows your contacts in a list. /ROSTER FULL Shows all your contacts in a list, even those who are offline. /ROSTER ADD [-nosub] Adds a JID to your contact list. (Use the parameter "-nosub" if you don't want to send a subscribe request.) /ROSTER REMOVE Removes a JID from your contact list. The subscriptions will be removed too. /ROSTER NAME Changes the name (or nickname) of a JID. /ROSTER GROUP Changes the group of a JID. /WHOIS /WHOIS Requests the vcard related to the JID. /VER / /VER Requests the software version of the resource. /QUOTE Sends server raw data without parsing. You need to make sure the value is XML valid. /XMPPCONNECT [-ssl] [-host ] [-port ] [/] /XMPPSERVER [-ssl] [-host ] [-port ] [/] See the "Connection" section of the STARTUP file. Subscription commands: ====================== These commands are useful if you want to manage the subscription of your contacts. /PRESENCE ACCEPT Accepts a subscription request, so the contact will be able to see your presence. /PRESENCE DENY Denies a subscription, so the contact won't see your presence anymore. /PRESENCE SUBSCRIBE Sends a subscription request to a JID. If the contact accepts your request, you'll be able to see his/her presence. /PRESENCE UNSUBSCRIBE Unsubscribes to the contact's presence, so you won't see his/her presence anymore. Subscription status: ==================== These are the subscription status displayed in the roster list with their description: both: The contact and you can see each other's presence. (not displayed) from: The contact can see your presence. to: You can see the contact's presence. none: The contact and you cannot see each other's presence. Settings: ========= In "xmpp" section: /SET xmpp_priority Sets the priority of your connection. It's a number between -128 and 127. Priority changes will take effect immediatly for all your connected accounts. (default: 0) /SET xmpp_priority_away Sets the priority of your connection when your are away. (default: -1) /SET xmpp_send_version ON/OFF Sends information about your client: name (irssi-xmpp), version and operating system. (default: ON) /SET xmpp_default_away_mode {away|chat|dnd|xa} Sets the default away mode when you just type "/AWAY ". (default: away) /SET xmpp_send_composing ON/OFF Enables or disables the sending of your chat state notifications. (default: ON) In "xmpp_lookandfeel" section: /SET xmpp_set_nick_as_username ON/OFF Sets whether your JID's username should be used as nick in query windows. If this setting is OFF, your nick will be your JID. If it's ON, your nick will be the username of your JID. (default: OFF) /SET xmpp_status_window ON/OFF Creates a new window that displays every status change of your contacts. (default: OFF) /SET xmpp_timestamp_format Sets the timestamp format that should be used to display the delayed messages. (default: %Y-%m-%d %H:%M) /SET xmpp_history_maxstanzas Sets the maximum number of messages that should be retrieved from the archives when joining a room. (default: 30) /SET xmpp_xml_console ON/OFF Creates a new window where the raw XML messages are displayed. Useful for debugging. (default: OFF) In "xmpp_proxy" section: See the "Proxy usage" section of this file. In "xmpp_roster" section: /SET xmpp_roster_show_offline ON/OFF Shows offline contacts in the roster. (default: ON) /SET xmpp_roster_show_unsubscribed ON/OFF Shows unsubscribed contacts in the roster when they are offline. (default: ON) /SET xmpp_roster_default_group Sets the default group where the contacts will be displayed if the group name is unspecified. (default: General) /SET xmpp_roster_service_name Sets the default group where the services and the transports will be displayed. (default: Agents/Transports) (Not used yet!) Away status: =========== In this section you can find the descriptions of each away status available in jabber: away: Away chat: Free for chat dnd: Do not disturb xa: Not available Proxy usage: ============ To connect to an account through a proxy, you must set these settings according to your proxy configuration. Please note that these settings are general so they affect all the jabber accounts you configured in irssi. /SET xmpp_use_proxy ON/OFF Enables or disables the proxy. (default: OFF) /SET xmpp_proxy_address /SET xmpp_proxy_port /SET xmpp_proxy_user /SET xmpp_proxy_password Sets the connection parameters to connect to the proxy. /SET xmpp_proxy_type Sets the type of the proxy. Currently, irssi-xmpp only supports the HTTP method. (default: http) Composing in the statusbar: =========================== irssi-xmpp supports the XEP-0085: Chat State Notifications, so you can see when your contacts are typing a messages with "composing" appearing in the statusbar. To add this statusbar element, you can use this command : /STATUSBAR WINDOW ADD xmpp_composing Or for example: /STATUSBAR WINDOW ADD -before barend -alignment right xmpp_composing docs/INTERNAL0000644000175000017500000000106012261357644010756 0ustar fsfsTODO: finnish writting this doc Sources layout: =============== src/core src/core/xep src/fe-common src/fe-common/xep src/fe-text Signals: ======== xmpp xml recv xmpp xml send xmpp recv message xmpp recv presence xmpp recv iq xmpp recv others xmpp send message xmpp send presence xmpp send iq xmpp send others xmpp ssl error xmpp server status xmpp presence online xmpp presence offline xmpp presence changed xmpp features xmpp server features xmpp composing show xmpp composing hide xmpp composing start xmpp composing stop xmpp vcard xmpp version docs/STARTUP0000644000175000017500000000233712261357644010714 0ustar fsfsRunning irssi-xmpp: =================== Usage: /LOAD xmpp Simply load the module in irssi. Currently you cannot load it automatically, unless using a script or something like that. The module should be placed in "~/.irssi/modules/", or you should load it with the full path. You can unload it using: /UNLOAD xmpp Connection: =========== Usage: /XMPPCONNECT [-ssl] [-host ] [-port ] [/] The "jid" is your Jabber ID (something like "username@server"). You can add "/" at the end of the "jid" to set your own resource. Please note that irssi-xmpp doesn't support SRV record (yet), so you must specify the host with the parameter "-host". You can also use /XMPPSERVER to replace the current connection. See the FAQ if you want to automatically connect to the server at startup If available, StartTLS will be used by default. Use the "-ssl" switch only if you want to use the deprecated SSL encryption. Automation: =========== If you want to automatically load the module and connect to an account, take a look at the FAQ. Everything is explained in it. Register: ========= You can register an account directly with irssi-xmpp using the command /XMPPREGISTER. help/0000755000175000017500000000000012261362415007612 5ustar fsfshelp/roster0000644000175000017500000000031012261362415011045 0ustar fsfs ROSTER [full] ROSTER add ROSTER remove ROSTER name ROSTER group This command includes various subcommands for handling your contact list. See also: PRESENCE help/xmppserver0000644000175000017500000000103212261357644011754 0ustar fsfs XMPPSERVER %|[-ssl] [-server ] [-port ] [/] -ssl: use SSL when connecting (deprecated, StartTLS will be used by default if this parameter is not specified) -host: the host -port: the port (if not specified, 5222 is used for a normal connection or 5223 for an SSL connection) This command disconnects the server in active window and connects to the new one. It will take the same arguments as /XMPPCONNECT. See also: XMPPCONNECT, CONNECT, SERVER, DISCONNECT, RECONNECT, RMRECONNS help/presence0000644000175000017500000000014612261362415011342 0ustar fsfs PRESENCE Handle presence subscription. See also: ROSTER help/xmppconnect0000644000175000017500000000076712261357644012115 0ustar fsfs XMPPCONNECT %|[-ssl] [-host ] [-port ] [/] -ssl: use SSL when connecting (deprecated, StartTLS will be used by default if this parameter is not specified) -host: the host -port: the port (if not specified, 5222 is used for a normal connection or 5223 for an SSL connection) This command makes irssi to connect to specified XMPP account. Current connections are kept and a new one is created. See also: XMPPSERVER, SERVER, DISCONNECT, RMRECONNS Makefile0000644000175000017500000000205612261362415010325 0ustar fsfsinclude config.mk all clean user-install user-uninstall: @cd src/ && ${MAKE} $@ install: @cd src/ && ${MAKE} $@ @${MAKE} doc-install help-install uninstall: doc-uninstall help-uninstall @cd src/ && ${MAKE} $@ doc-install: @echo installing documentation files to ${DESTDIR}${IRSSI_DOC}/irssi-xmpp @install -d ${DESTDIR}${IRSSI_DOC}/irssi-xmpp @cd docs/ && install -m 644 FAQ GENERAL MUC STARTUP XEP ${DESTDIR}${IRSSI_DOC}/irssi-xmpp doc-uninstall: @echo uninstalling documentation files from ${DESTDIR}${IRSSI_DOC}/irssi-xmpp @rm -rf ${DESTDIR}${IRSSI_DOC}/irssi-xmpp help-install: @echo installing command help files to ${DESTDIR}${IRSSI_HELP} @install -d ${DESTDIR}${IRSSI_HELP} @cd help/ && install -m 644 presence roster xmppconnect xmppserver ${DESTDIR}${IRSSI_HELP} help-uninstall: @echo uninstalling command help files from ${DESTDIR}${IRSSI_HELP} @cd ${DESTDIR}${IRSSI_HELP} && rm -f presence roster xmppconnect xmppserver .PHONY: all clean install uninstall user-install user-uninstall doc-install doc-uninstall help-install help-uninstall NEWS0000644000175000017500000000374412261357644007401 0ustar fsfs0.52 - 15/02/2012 - Add a way to dynamicly change the priority while away (setting "xmpp_priority_away") - No more password prompt on reconnection - Don't forget the resource part of the jid on reconnection - Fix MUC invites to be compliant - and some minor bug, typo and spelling mistakes fixes 0.51 - 14/05/2010 + Add STARTTLS support (enabled by default if the parameter -ssl is not specified) - Rework the way connections are performed - Add a password prompt if no password was specified - Add a connection timeout in case there is no response from the server, so the connection will be reseted after a certain amount of time (setting "server_connect_timeout") - /CYCLE command - and many others minor changes and fixes 0.50 - 07/08/2009 + Complete rewrite with a modular architecture + Better integration in irssi, many bug fixes and a big code cleanup + Better support of XMPP + Multi-User Chat (XEP-0045), Entity Use Cases and Occupant Use Cases + Message Events (XEP-0022) and Chat State Notifications (XEP-0085) showed in the status-bar (status-bar "xmpp_composing"), you can disable events sending (setting "xmpp_send_composing") + XMPP Ping (XEP-0199) support using the command /PING, it also allows the lag-meter to work + Software Version (XEP-0092) support using /VER and vCard (XEP-0054) using /WHOIS (partial retrieve) + Delayed Delivery (XEP-0203) support + Better UTF-8 support + HTTP proxy support + commands /XMPPCONNECT and /XMPPSERVER to connect easily to an account + command /XMPPREGISTER to register an account using the In-Band Registration (XEP-0077) - /ME command on queries and rooms - tab completion of JIDs, resources, user names and groups (even with spaces) - changing the priority (setting "xmpp_priority") takes effect immediately - basic status changes window (setting "xmpp_status_window") and raw window (setting "xmpp_raw_window") - and many others minor changes and fixes README0000644000175000017500000000513112261362415007542 0ustar fsfsirssi-xmpp: =========== homepage: http://cybione.org/~irssi-xmpp/ About: ====== irssi-xmpp is an irssi plugin to connect to the Jabber network. Its main features are: o Sending and receiving messages in irssi's query windows o A roster with contact & resource tracking (contact list) o Contact management (add, remove, manage subscriptions) o MUC (Multi-User Chat) o Tab completion of commands, JIDs and resources o Message Events ("composing") o Support for multiple accounts o Unicode support (UTF-8) o StartTLS, SSL (deprecated) and HTTP proxy support o ... To deal with the XMPP protocol, it uses of the Loudmouth library. Written in C and released under the GNU General Public License version 2. Installation: ============= Requirement: o Loudmouth (>= 1.4.x): http://www.loudmouth-project.org/ o Irssi (>= 0.8.13) and its sources unpacked and configured: http://irssi.org/ Procedure: o edit the file "config.mk" if needed and export this environment variable: $ export IRSSI_INCLUDE=/path/to/irssi/sources o build the sources: $ make o install the module: - in your home directory: $ make user-install - in the base system: # make install Documentation: ============== In the directory "docs/": o STARTUP: Getting started o GENERAL: How to use irssi-xmpp and related commands o MUC: How to use Multi-User Chat and related commands o FAQ: Frequently Asked Questions and Troubleshooting o XEP: XMPP Extensions supported o INTERNAL: How irssi-xmpp works In the directory "help/" you can find the help files of each irssi-xmpp specific commands, which can be viewed in irssi with the command /HELP. Community/Bugs/Suggestions: =========================== Mailing-list: irssi-xmpp-list@lists.cybione.org to subscribe: irssi-xmpp-list+subscribe@lists.cybione.org to unsuscibre: irssi-xmpp-list+unsubscribe@lists.cybione.org archives: http://cybione.org/lists/irssi-xmpp-list/ MUC room: irssi-xmpp@chat.jabberfr.org archives: http://chat.jabberfr.org/logs/irssi-xmpp@chat.jabberfr.org/?C=M;O=D Bug tracker: https://gna.org/bugs/?group=irssi-xmpp If irssi crashes, please build irssi with debug symbols and the module irssi-xmpp in debug mode (take a look at "config.mk" to activate it). Then you can run irssi in gdb and print the backtrace ("bt full") when irssi crashes. Paste the backtrace in your message would help to fix this bug. Author: ======= Colin Didier (cdidier@cybione.org, xmpp:cdidier@im.cybione.org) src/0000755000175000017500000000000012261362415007451 5ustar fsfssrc/fe-common/0000755000175000017500000000000012261362415011331 5ustar fsfssrc/fe-common/module-formats.h0000644000175000017500000000217412261362415014444 0ustar fsfs#include "formats.h" enum { XMPPTXT_MODULE_NAME, XMPPTXT_FILL_1, XMPPTXT_FORMAT_NAME, XMPPTXT_FORMAT_JID, XMPPTXT_FORMAT_RESOURCE, XMPPTXT_FORMAT_RESOURCE_SHOW, XMPPTXT_FORMAT_RESOURCE_STATUS, XMPPTXT_FORMAT_SUBSCRIPTION, XMPPTXT_FILL_2, XMPPTXT_ROSTER_GROUP, XMPPTXT_ROSTER_CONTACT, XMPPTXT_BEGIN_OF_ROSTER, XMPPTXT_END_OF_ROSTER, XMPPTXT_NOT_IN_ROSTER, XMPPTXT_FILL_3, XMPPTXT_SUBSCRIBE, XMPPTXT_SUBSCRIBED, XMPPTXT_UNSUBSCRIBE, XMPPTXT_UNSUBSCRIBED, XMPPTXT_FILL_4, XMPPTXT_MESSAGE_EVENT, XMPPTXT_MESSAGE_NOT_DELIVERED, XMPPTXT_MESSAGE_TIMESTAMP, XMPPTXT_FILL_5, XMPPTXT_QUERY_AKA, XMPPTXT_FILL_6, XMPPTXT_CHANNEL_JOINERROR, XMPPTXT_FILL_7, XMPPTXT_PRESENCE_CHANGE, XMPPTXT_PRESENCE_CHANGE_REASON, XMPPTXT_FILL_8, XMPPTXT_VCARD, XMPPTXT_VCARD_VALUE, XMPPTXT_VCARD_SUBVALUE, XMPPTXT_END_OF_VCARD, XMPPTXT_FILL_9, XMPPTXT_RAW_IN_HEADER, XMPPTXT_RAW_OUT_HEADER, XMPPTXT_RAW_MESSAGE, XMPPTXT_DEFAULT_EVENT, XMPPTXT_DEFAULT_ERROR, XMPPTXT_FILL_10, XMPPTXT_REGISTRATION_STARTED, XMPPTXT_REGISTRATION_SUCCEED, XMPPTXT_REGISTRATION_FAILED, }; extern FORMAT_REC fecommon_xmpp_formats[]; src/fe-common/fe-xmpp-messages.h0000644000175000017500000000024312261362415014662 0ustar fsfs#ifndef __FE_XMPP_MESSAGES_H #define __FE_XMPP_MESSAGES_H __BEGIN_DECLS void fe_xmpp_messages_init(void); void fe_xmpp_messages_deinit(void); __END_DECLS #endif src/fe-common/Makefile0000644000175000017500000000071212261362415012771 0ustar fsfsLIB= fe_xmpp SRCS= fe-xmpp-messages.c \ fe-xmpp-queries.c \ fe-xmpp-status.c \ fe-xmpp-windows.c \ fe-rosters.c \ fe-stanzas.c \ fe-xmpp-core.c \ module-formats.c \ xmpp-completion.c \ xmpp-formats.c \ xep/fe-composing.c \ xep/fe-delay.c \ xep/fe-muc.c \ xep/fe-ping.c \ xep/fe-registration.c \ xep/fe-vcard.c \ xep/fe-version.c \ xep/fe-xep.c LIB_INCS = -I../../src/fe-common LIB_LIBS = `pkg-config --libs glib-2.0` include ../rules.mk src/fe-common/fe-xmpp-windows.h0000644000175000017500000000023712261362415014550 0ustar fsfs#ifndef __FE_XMPP_WINDOWS_H #define __FE_XMPP_WINDOWS_H __BEGIN_DECLS void fe_xmpp_windows_init(void); void fe_xmpp_windows_deinit(void); __END_DECLS #endif src/fe-common/fe-xmpp-status.h0000644000175000017500000000047512261362415014405 0ustar fsfs#ifndef __FE_XMPP_STATUS_H #define __FE_XMPP_STATUS_H extern const char *fe_xmpp_presence_show[]; __BEGIN_DECLS char *fe_xmpp_status_get_window_name(XMPP_SERVER_REC *); WINDOW_REC *fe_xmpp_status_get_window(XMPP_SERVER_REC *); void fe_xmpp_status_init(void); void fe_xmpp_status_deinit(void); __END_DECLS #endif src/fe-common/module-formats.c0000644000175000017500000000660112261362415014436 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "formats.h" FORMAT_REC fecommon_xmpp_formats[] = { { MODULE_NAME, "XMPP", 0, { 0 } }, /* ---- */ { NULL, "Format", 0, { 0 } }, { "format_name", "{nick $0} {nickhost $1}", 2, { 0, 0 } }, { "format_jid", "{nick $0}", 1, { 0 } }, { "format_resource", "{comment $0{hilight $1}($2)$3}", 4, { 0, 0, 0, 0 } }, { "format_resource_show", "($0)", 1, { 0 } }, { "format_resource_status", ": $0", 1, { 0 } }, { "format_subscription", "(subscription: $0)", 1, { 0 } }, /* ---- */ { NULL, "Roster", 0, { 0 } }, { "roster_group", " {hilight $0}:", 1, { 0 } }, { "roster_contact", " ({hilight $0}) $1 $2 $3", 4, { 0, 0, 0, 0 } }, { "begin_of_roster", "ROSTER: {nick $0} $1 $2", 3, { 0, 0, 0 } }, { "end_of_roster", "End of ROSTER", 0, { 0 } }, { "not_in_roster", "{nick $0}: not in the roster", 1, { 0 } }, /* ---- */ { NULL, "Subscription", 0, { 0 } }, { "suscribe", "$0: wants to subscribe to your presence {comment $1} (accept or deny?)", 2, { 0, 0 } }, { "suscribed", "$0: wants you to see his/her presence", 1, { 0 } }, { "unsuscribe", "$0: doesn't want to see your presence anymore", 1 , { 0 } }, { "unsuscribed", "$0: doesn't want you to see his/her presence anymore", 1 , { 0 } }, /* ---- */ { NULL, "Message", 0, { 0 } }, { "message_event", "$0: $1", 2, { 0, 0 } }, { "message_not_delivered", "$0: cannot deliver message {comment $1}", 2, { 0, 0 } }, { "message_timestamp", "[{timestamp $0}] $1", 2, { 0, 0 } }, /* ---- */ { NULL, "Queries", 0, { 0 } }, { "query_aka", "{nick $0}: Also known as {nick $1}", 2, { 0, 0 } }, /* ---- */ { NULL, "Channel", 0, { 0 } }, { "joinerror", "Cannot join to room {channel $0} {comment $1}", 2, { 0, 0 } }, /* ---- */ { NULL, "Presence", 0, { 0 } }, { "presence_change", "$0: is now {hilight $1}", 2, { 0, 0 } }, { "presence_change_reason", "$0: is now {hilight $1} {comment $2}", 3, { 0, 0, 0 } }, /* ---- */ { NULL, "VCard", 0, { 0 } }, { "vcard", "{nick $0} {nickhost $1}", 2, { 0, 0 } }, { "vcard_value", " $0: $1", 2, { 0, 0 } }, { "vcard_subvalue", " $0: $1", 2, { 0, 0 } }, { "end_of_vcard", "End of VCARD", 0, { 0 } }, /* ---- */ { NULL, "Misc", 0, { 0 } }, { "raw_in_header", "RECV[$0]:", 1, { 0 } }, { "raw_out_header", "SEND[$0]:", 1, { 0 } }, { "raw_message", "$0", 1, { 0 } }, { "default_event", "$1 $2", 3, { 0, 0, 0 } }, { "default_error", "ERROR $1 $2", 3, { 0, 0, 0 } }, { NULL, "Regisration", 0, { 0 } }, { "xmpp_registration_started", "Registering {nick $0@$1}...", 2, { 0, 0 } }, { "xmpp_registration_succeed", "Registration of {nick $0@$1} succeeded", 2, { 0, 0 } }, { "xmpp_registration_failed", "Registration of {nick $0@$1} failed {comment $2}", 3, { 0, 0, 0 } }, { NULL, NULL, 0, { 0 } } }; src/fe-common/fe-rosters.c0000644000175000017500000002407212261362415013573 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "settings.h" #include "signals.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "fe-xmpp-status.h" static gboolean user_is_shown(XMPP_ROSTER_USER_REC *user) { g_return_val_if_fail(user != NULL, FALSE); return user->resources != NULL || (user->subscription == XMPP_SUBSCRIPTION_BOTH && settings_get_bool("xmpp_roster_show_offline")) || (user->subscription != XMPP_SUBSCRIPTION_BOTH && (settings_get_bool("xmpp_roster_show_unsubscribed") || settings_get_bool("xmpp_roster_show_offline"))); } static void show_group(XMPP_SERVER_REC *server, XMPP_ROSTER_GROUP_REC *group) { g_return_if_fail(IS_SERVER(server)); g_return_if_fail(group != NULL); printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_ROSTER_GROUP, (group->name != NULL) ? group->name : settings_get_str("xmpp_roster_default_group")); } static const char * get_first_show(GSList *list) { if (list == NULL) return NULL; return xmpp_presence_show[ ((XMPP_ROSTER_RESOURCE_REC *)list->data)->show]; } static char * get_resources(XMPP_SERVER_REC *server, GSList *list) { GSList *tmp; GString *resources; XMPP_ROSTER_RESOURCE_REC *resource; char *show, *status, *status_str, *priority, *text; if (list == NULL) return NULL; resources = g_string_new(NULL); for (tmp = list; tmp != NULL; tmp = tmp->next) { resource = tmp->data; show = (resource->show == XMPP_PRESENCE_AVAILABLE) ? NULL : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_RESOURCE_SHOW, xmpp_presence_show[resource->show]); status_str = g_strdup(resource->status); status = (resource->status == NULL) ? NULL : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_RESOURCE_STATUS, status_str); g_free(status_str); priority = g_strdup_printf("%d", resource->priority); text = format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_RESOURCE, show, resource->name, priority, status); g_free(show); g_free(status); g_free(priority); g_string_append(resources, text); g_free(text); } text = resources->str; g_string_free(resources, FALSE); return text; } static void show_user(XMPP_SERVER_REC *server, XMPP_ROSTER_USER_REC *user) { const char *first_show; char *name, *resources, *subscription; g_return_if_fail(IS_SERVER(server)); g_return_if_fail(user != NULL); if (user->resources == NULL) first_show = xmpp_presence_show[user->error ? XMPP_PRESENCE_ERROR : XMPP_PRESENCE_UNAVAILABLE]; else first_show = get_first_show(user->resources); name = user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, user->jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, user->jid); resources = get_resources(server, user->resources); subscription = user->subscription == XMPP_SUBSCRIPTION_BOTH ? NULL : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_SUBSCRIPTION, xmpp_subscription[user->subscription]); printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_ROSTER_CONTACT, first_show, name, resources, subscription); g_free(name); g_free(resources); g_free(subscription); } static void show_begin_of_roster(XMPP_SERVER_REC *server) { char *show, *status, *priority, *text, *resources; g_return_if_fail(IS_XMPP_SERVER(server)); show = (server->show == XMPP_PRESENCE_AVAILABLE) ? NULL : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_RESOURCE_SHOW, xmpp_presence_show[server->show]); status = (server->away_reason == NULL || strcmp(server->away_reason, " ") == 0) ? NULL : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_RESOURCE_STATUS, server->away_reason); priority = g_strdup_printf("%d", server->priority); text = format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_RESOURCE, show, server->resource, priority, status); g_free(show); g_free(status); g_free(priority); resources = get_resources(server, server->my_resources); printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_BEGIN_OF_ROSTER, server->jid, text, resources); g_free(text); g_free(resources); } static void sig_roster_show(XMPP_SERVER_REC *server) { GSList *gl, *ul; XMPP_ROSTER_GROUP_REC *group; XMPP_ROSTER_USER_REC *user; g_return_if_fail(IS_XMPP_SERVER(server)); show_begin_of_roster(server); for (gl = server->roster; gl != NULL; gl = gl->next) { group = gl->data; /* don't show groups with only offline users */ for (ul = group->users; ul != NULL && !user_is_shown(ul->data); ul = ul->next); if (ul == NULL) continue; show_group(server, group); for (ul = group->users; ul != NULL; ul = ul->next) { user = ul->data; if (user_is_shown(user)) show_user(server, user); } } printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_END_OF_ROSTER); } static void sig_not_in_roster(XMPP_SERVER_REC *server, const char *jid) { g_return_if_fail(IS_SERVER(server)); g_return_if_fail(jid != NULL); printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CLIENTERROR, XMPPTXT_NOT_IN_ROSTER, jid); } static void sig_subscribe(XMPP_SERVER_REC *server, const char *jid, const char *status) { XMPP_ROSTER_USER_REC *user; char *name; g_return_if_fail(IS_SERVER(server)); g_return_if_fail(jid != NULL); user = rosters_find_user(server->roster, jid, NULL, NULL); name = user != NULL && user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, jid); if (settings_get_bool("xmpp_status_window")) printformat_module_window(MODULE_NAME, fe_xmpp_status_get_window(server), MSGLEVEL_CRAP, XMPPTXT_SUBSCRIBE, name, status); else printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_SUBSCRIBE, name, status); g_free(name); } static void sig_subscribed(XMPP_SERVER_REC *server, const char *jid) { XMPP_ROSTER_USER_REC *user; char *name; g_return_if_fail(IS_SERVER(server)); g_return_if_fail(jid != NULL); user = rosters_find_user(server->roster, jid, NULL, NULL); name = user != NULL && user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, jid); if (settings_get_bool("xmpp_status_window")) printformat_module_window(MODULE_NAME, fe_xmpp_status_get_window(server), MSGLEVEL_CRAP, XMPPTXT_SUBSCRIBED, name); else printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_SUBSCRIBED, name); g_free(name); } static void sig_unsubscribe(XMPP_SERVER_REC *server, const char *jid) { XMPP_ROSTER_USER_REC *user; char *name; g_return_if_fail(IS_SERVER(server)); g_return_if_fail(jid != NULL); user = rosters_find_user(server->roster, jid, NULL, NULL); name = user != NULL && user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, jid); if (settings_get_bool("xmpp_status_window")) printformat_module_window(MODULE_NAME, fe_xmpp_status_get_window(server), MSGLEVEL_CRAP, XMPPTXT_UNSUBSCRIBE, name); else printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_UNSUBSCRIBE, name); g_free(name); } static void sig_unsubscribed(XMPP_SERVER_REC *server, const char *jid) { XMPP_ROSTER_USER_REC *user; char *name; g_return_if_fail(IS_SERVER(server)); g_return_if_fail(jid != NULL); user = rosters_find_user(server->roster, jid, NULL, NULL); name = user != NULL && user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, jid); if (settings_get_bool("xmpp_status_window")) printformat_module_window(MODULE_NAME, fe_xmpp_status_get_window(server), MSGLEVEL_CRAP, XMPPTXT_UNSUBSCRIBED, name); else printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CRAP, XMPPTXT_UNSUBSCRIBED, name); g_free(name); } void fe_rosters_init(void) { signal_add("xmpp roster show", sig_roster_show); signal_add("xmpp not in roster", sig_not_in_roster); signal_add("xmpp presence subscribe", sig_subscribe); signal_add("xmpp presence subscribed", sig_subscribed); signal_add("xmpp presence unsubscribe", sig_unsubscribe); signal_add("xmpp presence unsubscribed", sig_unsubscribed); settings_add_str("xmpp_roster", "xmpp_roster_default_group", "General"); settings_add_str("xmpp_roster", "xmpp_roster_service_name", "Agents/Services"); settings_add_bool("xmpp_roster", "xmpp_roster_show_offline", TRUE); settings_add_bool("xmpp_roster", "xmpp_roster_show_unsubscribed", TRUE); } void fe_rosters_deinit(void) { signal_remove("xmpp roster show", sig_roster_show); signal_remove("xmpp not in roster", sig_not_in_roster); signal_remove("xmpp presence subscribe", sig_subscribe); signal_remove("xmpp presence subscribed", sig_subscribed); signal_remove("xmpp presence unsubscribe", sig_unsubscribe); signal_remove("xmpp presence unsubscribed", sig_unsubscribed); } src/fe-common/fe-xmpp-messages.c0000644000175000017500000002157012261362415014663 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "channels.h" #include "levels.h" #include "module-formats.h" #include "nicklist.h" #include "printtext.h" #include "recode.h" #include "settings.h" #include "signals.h" #include "window-items.h" #include "fe-queries.h" #include "fe-common/core/module-formats.h" #include "fe-common/core/fe-messages.h" #include "fe-common/irc/module-formats.h" #include "irssi-version.h" #include "xmpp-servers.h" static void sig_history(SERVER_REC *server, const char *msg, const char *nick, const char *target, const char *stamp, gpointer gpointer_type) { void *item; char *text, *freemsg = NULL; int level, type; g_return_if_fail(server != NULL); g_return_if_fail(msg != NULL); g_return_if_fail(nick != NULL); g_return_if_fail(target != NULL); type = GPOINTER_TO_INT(gpointer_type); level = MSGLEVEL_NO_ACT | MSGLEVEL_NOHILIGHT | (type == SEND_TARGET_CHANNEL ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS); item = type == SEND_TARGET_CHANNEL ? (void *)channel_find(server, target) : query_find(server, nick); if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis(item, msg); /* MUC */ if (type == SEND_TARGET_CHANNEL) { CHANNEL_REC *chanrec = item; int print_channel; char *nickmode; print_channel = chanrec == NULL || !window_item_is_active((WI_ITEM_REC *)chanrec); if (!print_channel && settings_get_bool("print_active_channel") && window_item_window((WI_ITEM_REC *)chanrec)->items->next != NULL) print_channel = TRUE; nickmode = channel_get_nickmode(chanrec, nick); text = !print_channel ? format_get_text(CORE_MODULE_NAME, NULL, server, target, TXT_PUBMSG, nick, msg, nickmode) : format_get_text(CORE_MODULE_NAME, NULL, server, target, TXT_PUBMSG_CHANNEL, nick, target, msg, nickmode); g_free(nickmode); /* General */ } else text = format_get_text(CORE_MODULE_NAME, NULL, server, target, item == NULL ? TXT_MSG_PRIVATE : TXT_MSG_PRIVATE_QUERY, nick, nick, msg); printformat_module(MODULE_NAME, server, target, level, XMPPTXT_MESSAGE_TIMESTAMP, stamp, text); g_free_not_null(freemsg); g_free(text); } static void sig_history_action(SERVER_REC *server, const char *msg, const char *nick, const char *target, const char *stamp, gpointer gpointer_type) { void *item; char *text, *freemsg = NULL; int level, type; g_return_if_fail(server != NULL); g_return_if_fail(msg != NULL); g_return_if_fail(nick != NULL); g_return_if_fail(target != NULL); type = GPOINTER_TO_INT(gpointer_type); level = MSGLEVEL_ACTIONS | MSGLEVEL_NO_ACT | MSGLEVEL_NOHILIGHT | (type == SEND_TARGET_CHANNEL ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS); item = type == SEND_TARGET_CHANNEL ? (void *)channel_find(server, target) : query_find(server, nick); if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis(item, msg); /* MUC */ if (type == SEND_TARGET_CHANNEL) { if (item && window_item_is_active(item)) text = format_get_text(IRC_MODULE_NAME, NULL, server, target, IRCTXT_ACTION_PUBLIC, nick, msg); else text = format_get_text(IRC_MODULE_NAME, NULL, server, target, IRCTXT_ACTION_PUBLIC_CHANNEL, nick, target, msg); /* General */ } else text = format_get_text(IRC_MODULE_NAME, NULL, server, nick, (item == NULL) ? IRCTXT_ACTION_PRIVATE : IRCTXT_ACTION_PRIVATE_QUERY, nick, nick, msg); printformat_module(MODULE_NAME, server, target, level, XMPPTXT_MESSAGE_TIMESTAMP, stamp, text); g_free(freemsg); } static void sig_action(SERVER_REC *server, const char *msg, const char *nick, const char *target, gpointer gpointer_type) { void *item; char *freemsg = NULL; int level, type; g_return_if_fail(server != NULL); g_return_if_fail(msg != NULL); g_return_if_fail(nick != NULL); g_return_if_fail(target != NULL); type = GPOINTER_TO_INT(gpointer_type); level = MSGLEVEL_ACTIONS | (type == SEND_TARGET_CHANNEL ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS); item = type == SEND_TARGET_CHANNEL ? (void *)channel_find(server, target) : privmsg_get_query(SERVER(server), nick, FALSE, level); if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis(item, msg); /* MUC */ if (type == SEND_TARGET_CHANNEL) { if (item && window_item_is_active(item)) printformat_module(IRC_MODULE_NAME, server, target, level, IRCTXT_ACTION_PUBLIC, nick, msg); else printformat_module(IRC_MODULE_NAME, server, target, level, IRCTXT_ACTION_PUBLIC_CHANNEL, nick, target, msg); /* General */ } else printformat_module(IRC_MODULE_NAME, server, nick, level, (item == NULL) ? IRCTXT_ACTION_PRIVATE : IRCTXT_ACTION_PRIVATE_QUERY, nick, nick, msg); g_free(freemsg); } static void sig_own_action(SERVER_REC *server, const char *msg, const char *target, gpointer gpointer_type) { void *item; char *freemsg = NULL; int type; g_return_if_fail(server != NULL); g_return_if_fail(msg != NULL); g_return_if_fail(target != NULL); type = GPOINTER_TO_INT(gpointer_type); item = type == SEND_TARGET_CHANNEL ? (void *)channel_find(server, target) : query_find(server, target); if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis(item, msg); printformat_module(IRC_MODULE_NAME, server, target, MSGLEVEL_ACTIONS | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT | ((type == SEND_TARGET_CHANNEL) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS), (item != NULL) ? IRCTXT_OWN_ACTION : IRCTXT_OWN_ACTION_TARGET, server->nick, msg, target); g_free(freemsg); } static void sig_error(XMPP_SERVER_REC *server, const char *full_jid, const char *msg) { g_return_if_fail(server != NULL); g_return_if_fail(full_jid != NULL); printformat_module(MODULE_NAME, server, full_jid, MSGLEVEL_CRAP, XMPPTXT_MESSAGE_NOT_DELIVERED, full_jid, msg); } static void sig_message_own_public(SERVER_REC *server, char *msg, char *target) { WINDOW_REC *window; CHANNEL_REC *channel; char *nick, *nickmode, *freemsg = NULL, *recoded; gboolean print_channel; g_return_if_fail(server != NULL); g_return_if_fail(msg != NULL); g_return_if_fail(target != NULL); if (!IS_XMPP_SERVER(server)) return; channel = channel_find(server, target); if (channel == NULL || channel->ownnick == NULL) return; nick = channel->ownnick->nick; nickmode = channel_get_nickmode(CHANNEL(channel), nick); window = (channel == NULL) ? NULL : window_item_window((WI_ITEM_REC *)channel); print_channel = (window == NULL || window->active != (WI_ITEM_REC *) channel); if (!print_channel && settings_get_bool("print_active_channel") && window != NULL && g_slist_length(window->items) > 1) print_channel = TRUE; if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis((WI_ITEM_REC *)channel, msg); /* ugly from irssi: recode the sent message back for printing */ recoded = recode_in(SERVER(server), msg, target); if (!print_channel) printformat_module(CORE_MODULE_NAME, server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, TXT_OWN_MSG, nick, recoded, nickmode); else printformat_module(CORE_MODULE_NAME, server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, TXT_OWN_MSG_CHANNEL, nick, target, recoded, nickmode); g_free(recoded); g_free(nickmode); g_free_not_null(freemsg); signal_stop(); /* emit signal for chat-completion */ } static void sig_message_ignore(XMPP_SERVER_REC *server) { if (IS_XMPP_SERVER(server)) signal_stop(); } void fe_xmpp_messages_init(void) { signal_add("message xmpp history", sig_history); signal_add("message xmpp history action", sig_history_action); signal_add("message xmpp action", sig_action); signal_add("message xmpp own_action", sig_own_action); signal_add("message xmpp error", sig_error); signal_add_first("message xmpp own_public", sig_message_own_public); signal_add_first("message own_public", sig_message_ignore); } void fe_xmpp_messages_deinit(void) { signal_remove("message xmpp history", sig_history); signal_remove("message xmpp history action", sig_history_action); signal_remove("message xmpp action", sig_action); signal_remove("message xmpp own_action", sig_own_action); signal_remove("message xmpp error", sig_error); signal_remove("message xmpp own_public", sig_message_own_public); signal_remove("message own_public", sig_message_ignore); } src/fe-common/fe-xmpp-queries.h0000644000175000017500000000023712261362415014533 0ustar fsfs#ifndef __FE_XMPP_QUERIES_H #define __FE_XMPP_QUERIES_H __BEGIN_DECLS void fe_xmpp_queries_init(void); void fe_xmpp_queries_deinit(void); __END_DECLS #endif src/fe-common/xmpp-completion.h0000644000175000017500000000023712261362415014637 0ustar fsfs#ifndef __XMPP_COMPLETION_H #define __XMPP_COMPLETION_H __BEGIN_DECLS void xmpp_completion_init(void); void xmpp_completion_deinit(void); __END_DECLS #endif src/fe-common/fe-xmpp-status.c0000644000175000017500000000763712261362415014407 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "settings.h" #include "signals.h" #include "window-items.h" #include "xmpp-servers.h" #include "rosters-tools.h" const char *fe_xmpp_presence_show[] = { "Offline", "error", "Not Available", "Busy", "Away", "Available", "Free for Chat" }; static char * get_window_name(XMPP_SERVER_REC *server) { g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); return g_strconcat("(", (server->connrec->chatnet == NULL || *server->connrec->chatnet == '\0') ? server->jid : server->connrec->chatnet, ")", (void *)NULL); } char * fe_xmpp_status_get_window_name(XMPP_SERVER_REC *server) { WINDOW_REC *window; char *name; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); if ((name = get_window_name(server)) == NULL) return NULL; window = window_find_name(name); g_free(name); return (window != NULL) ? window->name : NULL; } WINDOW_REC * fe_xmpp_status_get_window(XMPP_SERVER_REC *server) { WINDOW_REC *window; char *name; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); name = get_window_name(server); if ((window = window_find_name(name)) == NULL) { window = window_create(NULL, TRUE); window_set_name(window, name); window_change_server(window, server); } g_free(name); return window; } static void sig_presence_changed(XMPP_SERVER_REC *server, const char *full_jid, int show, const char *status) { XMPP_ROSTER_USER_REC *user; WINDOW_REC *window; const char *msg; char *name; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(full_jid != NULL); g_return_if_fail(0 <= show && show < XMPP_PRESENCE_SHOW_LEN); window = fe_xmpp_status_get_window(server); msg = fe_xmpp_presence_show[show]; user = rosters_find_user(server->roster, full_jid, NULL, NULL); name = user != NULL && user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, full_jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, full_jid); if (status != NULL) printformat_module_window(MODULE_NAME, window, MSGLEVEL_CRAP, XMPPTXT_PRESENCE_CHANGE_REASON, name, msg, status); else printformat_module_window(MODULE_NAME, window, MSGLEVEL_CRAP, XMPPTXT_PRESENCE_CHANGE, name, msg); g_free(name); } static void sig_setup_changed(void) { signal_remove("xmpp presence changed", sig_presence_changed); if (settings_get_bool("xmpp_status_window")) signal_add("xmpp presence changed", sig_presence_changed); } static void sig_server_connecting(XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER(server)) return; if (settings_get_bool("xmpp_status_window")) fe_xmpp_status_get_window(server); } void fe_xmpp_status_init(void) { signal_add("server connecting", (SIGNAL_FUNC)sig_server_connecting); signal_add("setup changed", (SIGNAL_FUNC)sig_setup_changed); settings_add_bool("xmpp_lookandfeel", "xmpp_status_window", FALSE); if (settings_get_bool("xmpp_status_window")) signal_add("xmpp presence changed", sig_presence_changed); } void fe_xmpp_status_deinit(void) { signal_remove("server connecting", sig_server_connecting); signal_remove("setup changed", sig_setup_changed); signal_remove("xmpp presence changed", sig_presence_changed); } src/fe-common/fe-xmpp-queries.c0000644000175000017500000000571412261362415014533 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "signals.h" #include "window-items.h" #include "xmpp-queries.h" #include "rosters-tools.h" #include "fe-xmpp-status.h" static void sig_presence_changed(XMPP_SERVER_REC *server, const char *full_jid, int show, const char *status) { XMPP_QUERY_REC *rec; XMPP_ROSTER_USER_REC *user; const char *msg; char *name; g_return_if_fail(server != NULL); g_return_if_fail(full_jid != NULL); g_return_if_fail(0 <= show && show < XMPP_PRESENCE_SHOW_LEN); if ((rec = xmpp_query_find(server, full_jid)) == NULL) return; msg = fe_xmpp_presence_show[show]; user = rosters_find_user(server->roster, full_jid, NULL, NULL); name = user != NULL && user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, full_jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, full_jid); if (status != NULL) printformat_module(MODULE_NAME, server, full_jid, MSGLEVEL_CRAP, XMPPTXT_PRESENCE_CHANGE_REASON, name, msg, status); else printformat_module(MODULE_NAME, server, full_jid, MSGLEVEL_CRAP, XMPPTXT_PRESENCE_CHANGE, name, msg); } static void sig_query_raise(XMPP_SERVER_REC *server, QUERY_REC *query) { WINDOW_REC *window; g_return_if_fail(query != NULL); window = window_item_window(query); if (window != active_win) window_set_active(window); window_item_set_active(active_win, (WI_ITEM_REC *)query); } static void sig_query_created(XMPP_QUERY_REC *query, int automatic) { XMPP_ROSTER_USER_REC *user; if (!IS_XMPP_QUERY(query)) return; user = rosters_find_user(query->server->roster, query->name, NULL, NULL); if (user == NULL || user->name == NULL) return; printformat_module(MODULE_NAME, query->server, query->name, MSGLEVEL_CRAP, XMPPTXT_QUERY_AKA, user->jid, user->name); } void fe_xmpp_queries_init(void) { signal_add("xmpp query raise", sig_query_raise); signal_add("xmpp presence changed", sig_presence_changed); signal_add_last("query created", sig_query_created); } void fe_xmpp_queries_deinit(void) { signal_remove("xmpp query raise", sig_query_raise); signal_remove("xmpp presence changed", sig_presence_changed); signal_remove("query created", sig_query_created); } src/fe-common/fe-rosters.h0000644000175000017500000000021412261362415013570 0ustar fsfs#ifndef __FE_ROSTERS_H #define __FE__ROSTERS_H __BEGIN_DECLS void fe_rosters_init(void); void fe_rosters_deinit(void); __END_DECLS #endif src/fe-common/xmpp-formats.c0000644000175000017500000000204412261362415014132 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "formats.h" #include "signals.h" static void sig_strip_codes(const char *in, const char **out) { if (out != NULL) *out = strip_codes(in); } void xmpp_formats_init(void) { signal_add("xmpp formats strip codes", sig_strip_codes); } void xmpp_formats_deinit(void) { signal_remove("xmpp formats strip codes", sig_strip_codes); } src/fe-common/fe-stanzas.h0000644000175000017500000000021312261362415013551 0ustar fsfs#ifndef __FE_STANZAS_H #define __FE_STANZAS_H __BEGIN_DECLS void fe_stanzas_init(void); void fe_stanzas_deinit(void); __END_DECLS #endif src/fe-common/xmpp-formats.h0000644000175000017500000000022312261362415014134 0ustar fsfs#ifndef __XMPP_FORMATS_H #define __XMPP_FORMATS_H __BEGIN_DECLS void xmpp_formats_init(void); void xmpp_formats_deinit(void); __END_DECLS #endif src/fe-common/fe-xmpp-windows.c0000644000175000017500000000264212261362415014545 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "channels.h" #include "signals.h" #include "window-items.h" #include "xmpp-servers.h" /* * Hack to get the name of the current XMPP channel which is necessary * to open a query with a nick in the channel * (because its jid is like: channel@host/nick) */ static void sig_get_active_channel(const char **name) { *name = IS_XMPP_SERVER(active_win->active_server) && IS_CHANNEL(active_win->active) ? ((CHANNEL_REC *)active_win->active)->name : NULL; } void fe_xmpp_windows_init(void) { signal_add("xmpp windows get active channel", sig_get_active_channel); } void fe_xmpp_windows_deinit(void) { signal_remove("xmpp windows get active channel", sig_get_active_channel); } src/fe-common/fe-xmpp-core.c0000644000175000017500000000511412261362415014000 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "core.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "servers-setup.h" #include "settings.h" #include "signals.h" #include "themes.h" #include "fe-xmpp-messages.h" #include "fe-xmpp-queries.h" #include "fe-xmpp-status.h" #include "fe-xmpp-windows.h" #include "fe-rosters.h" #include "fe-stanzas.h" #include "xmpp-completion.h" #include "xmpp-formats.h" #include "xep/fe-xep.h" static void sig_server_status(SERVER_REC *server, const char *msg) { printformat_module(MODULE_NAME, server, NULL, MSGLEVEL_CLIENTNOTICE, XMPPTXT_DEFAULT_EVENT, NULL, msg, NULL); } static void sig_server_add_fill(SERVER_SETUP_REC *rec, GHashTable *optlist) { char *value; if ((value = g_hash_table_lookup(optlist, "xmppnet")) != NULL) { g_free_and_null(rec->chatnet); if (*value != '\0') rec->chatnet = g_strdup(value); } } void fe_xmpp_init(void) { theme_register(fecommon_xmpp_formats); signal_add("xmpp server status", sig_server_status); signal_add("server add fill", sig_server_add_fill); fe_xmpp_messages_init(); fe_xmpp_queries_init(); fe_xmpp_status_init(); fe_xmpp_windows_init(); fe_rosters_init(); fe_stanzas_init(); xmpp_completion_init(); xmpp_formats_init(); fe_xep_init(); module_register("xmpp", "fe"); /* load irssi-xmpp's fe-text submodule */ if (irssi_gui == IRSSI_GUI_TEXT) { char *cmd_line = g_strconcat(settings_get_str("cmdchars"), "load xmpp text", (void *)NULL); signal_emit("send command", 1, cmd_line); g_free(cmd_line); } } void fe_xmpp_deinit(void) { signal_remove("xmpp server status", sig_server_status); signal_remove("server add fill", sig_server_add_fill); fe_xmpp_messages_deinit(); fe_xmpp_queries_deinit(); fe_xmpp_status_deinit(); fe_xmpp_windows_deinit(); fe_rosters_deinit(); fe_stanzas_deinit(); xmpp_completion_deinit(); xmpp_formats_deinit(); fe_xep_deinit(); theme_unregister(); } src/fe-common/xep/0000755000175000017500000000000012261362415012125 5ustar fsfssrc/fe-common/xep/fe-ping.h0000644000175000017500000000017712261362415013630 0ustar fsfs#ifndef __FE_PING_H #define __FE_PING_H __BEGIN_DECLS void fe_ping_init(void); void fe_ping_deinit(void); __END_DECLS #endif src/fe-common/xep/fe-registration.h0000644000175000017500000000023712261362415015402 0ustar fsfs#ifndef __FE_REGISTRATION_H #define __FE_REGISTRATION_H __BEGIN_DECLS void fe_registration_init(void); void fe_registration_deinit(void); __END_DECLS #endif src/fe-common/xep/fe-ping.c0000644000175000017500000000235612261362415013624 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "levels.h" #include "printtext.h" #include "signals.h" #include "fe-common/irc/module-formats.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "../module-formats.h" static void sig_ping(XMPP_SERVER_REC *server, const char *jid, long usecs) { printformat_module(IRC_MODULE_NAME, server, jid, MSGLEVEL_CRAP, IRCTXT_CTCP_PING_REPLY, jid, usecs/1000, usecs%1000); } void fe_ping_init(void) { signal_add("xmpp ping", sig_ping); } void fe_ping_deinit(void) { signal_remove("xmpp ping", sig_ping); } src/fe-common/xep/fe-vcard.h0000644000175000017500000000020312261362415013760 0ustar fsfs#ifndef __FE_VCARD_H #define __FE_VCARD_H __BEGIN_DECLS void fe_vcard_init(void); void fe_vcard_deinit(void); __END_DECLS #endif src/fe-common/xep/fe-vcard.c0000644000175000017500000000422212261362415013760 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "levels.h" #include "printtext.h" #include "signals.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "tools.h" #include "../module-formats.h" struct vcard_user_data { XMPP_SERVER_REC *server; const char *jid; }; static void func_vcard_value(const char *key, const char *value, struct vcard_user_data *ud) { printformat_module(MODULE_NAME, ud->server, ud->jid, MSGLEVEL_CRAP, XMPPTXT_VCARD_VALUE, key, value); } #if 0 static void func_vcard_subvalue(const char *key, const char *value, struct vcard_user_data *ud) { printformat_module(MODULE_NAME, ud->server, ud->jid, MSGLEVEL_CRAP, XMPPTXT_VCARD_SUBVALUE, key, value); } #endif static void sig_vcard(XMPP_SERVER_REC *server, const char *jid, GHashTable *ht) { XMPP_ROSTER_USER_REC *user; struct vcard_user_data ud; char *name; user = rosters_find_user(server->roster, jid, NULL, NULL); name = user != NULL && user->name != NULL ? g_strdup(user->name) : xmpp_strip_resource(jid); printformat_module(MODULE_NAME, server, jid, MSGLEVEL_CRAP, XMPPTXT_VCARD, name, jid); g_free(name); ud.server = server; ud.jid = jid; g_hash_table_foreach(ht, (void (*)(gpointer, gpointer, gpointer))func_vcard_value, &ud); printformat_module(MODULE_NAME, server, jid, MSGLEVEL_CRAP, XMPPTXT_END_OF_VCARD); } void fe_vcard_init(void) { signal_add("xmpp vcard", sig_vcard); } void fe_vcard_deinit(void) { signal_remove("xmpp vcard", sig_vcard); } src/fe-common/xep/fe-muc.c0000644000175000017500000001560012261362415013447 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "ignore.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "signals.h" #include "window-items.h" #include "fe-common/core/module-formats.h" #include "fe-common/irc/module-formats.h" #include "xmpp-servers.h" #include "xmpp-commands.h" #include "rosters-tools.h" #include "xep/muc.h" #include "xep/muc-nicklist.h" static void sig_invite(XMPP_SERVER_REC *server, const char *from, const char *channame) { const char *name; name = rosters_get_name(server, from); if (name == NULL) name = from; printformat_module(CORE_MODULE_NAME, server, from, MSGLEVEL_INVITES, TXT_INVITE, name, channame, from); } static void sig_joinerror(MUC_REC *channel, gpointer error) { char *reason; g_return_if_fail(IS_MUC(channel)); switch(GPOINTER_TO_INT(error)) { case MUC_ERROR_PASSWORD_INVALID_OR_MISSING: reason = "Password required"; break; case MUC_ERROR_USER_BANNED: reason = "Banned from the room"; break; case MUC_ERROR_ROOM_NOT_FOUND: reason = "The room does not exist"; break; case MUC_ERROR_ROOM_CREATION_RESTRICTED: reason = "Room creation is restricted"; break; case MUC_ERROR_USE_RESERVED_ROOM_NICK: reason = "Your desired nick is reserved (Retrying with your alternate nick...)"; break; case MUC_ERROR_NOT_ON_MEMBERS_LIST: reason = "You are not on the member list"; break; case MUC_ERROR_NICK_IN_USE: reason = "Your desired nick is already in use (Retrying with your alternate nick...)"; break; case MUC_ERROR_MAXIMUM_USERS_REACHED: reason = "Maximum number of users has been reached"; default: reason = "Unknow reason"; } printformat_module(MODULE_NAME, channel->server, NULL, MSGLEVEL_CRAP, XMPPTXT_CHANNEL_JOINERROR, channel->name, reason); } static void sig_nick(MUC_REC *channel, NICK_REC *nick, const char *oldnick) { g_return_if_fail(IS_MUC(channel)); g_return_if_fail(nick != NULL); g_return_if_fail(oldnick != NULL); if (ignore_check(SERVER(channel->server), oldnick, nick->host, channel->nick, nick->nick, MSGLEVEL_NICKS)) return; printformat_module(CORE_MODULE_NAME, channel->server, channel->name, MSGLEVEL_NICKS, TXT_NICK_CHANGED, oldnick, nick->nick, channel->name, nick->host); } static void sig_own_nick(MUC_REC *channel, NICK_REC *nick, const char *oldnick) { g_return_if_fail(IS_MUC(channel)); g_return_if_fail(nick != NULL); g_return_if_fail(oldnick != NULL); if (channel->ownnick != nick) return; printformat_module(CORE_MODULE_NAME, channel->server, channel->name, MSGLEVEL_NICKS | MSGLEVEL_NO_ACT, TXT_YOUR_NICK_CHANGED, oldnick, nick->nick, channel->name, nick->host); } void sig_nick_in_use(MUC_REC *channel, const char *nick) { g_return_if_fail(IS_MUC(channel)); g_return_if_fail(nick != NULL); if (!channel->joined) return; printformat_module(IRC_MODULE_NAME, channel->server, channel->name, MSGLEVEL_CRAP, IRCTXT_NICK_IN_USE, nick); } static void sig_mode(MUC_REC *channel, const char *nickname, int affiliation, int role) { XMPP_NICK_REC *nick; char *mode, *affiliation_str, *role_str; g_return_if_fail(IS_MUC(channel)); g_return_if_fail(nickname != NULL); if ((nick = xmpp_nicklist_find(channel, nickname)) == NULL) return; switch (affiliation) { case XMPP_NICKLIST_AFFILIATION_OWNER: affiliation_str = "O"; break; case XMPP_NICKLIST_AFFILIATION_ADMIN: affiliation_str = "A"; break; case XMPP_NICKLIST_AFFILIATION_MEMBER: affiliation_str = "M"; break; case XMPP_NICKLIST_AFFILIATION_OUTCAST: affiliation_str = "U"; break; default: affiliation_str = ""; } switch (role) { case XMPP_NICKLIST_ROLE_MODERATOR: role_str = "m"; break; case XMPP_NICKLIST_ROLE_PARTICIPANT: role_str = "p"; break; case XMPP_NICKLIST_ROLE_VISITOR: role_str = "v"; break; default: role_str = ""; } if (*affiliation_str == '\0' && *role_str == '\0') return; mode = g_strconcat("+", affiliation_str, role_str, " ", nickname, (void *)NULL); if (ignore_check(SERVER(channel->server), nickname, nick->host, channel->name, mode, MSGLEVEL_MODES)) goto out; printformat_module(IRC_MODULE_NAME, channel->server, channel->name, MSGLEVEL_MODES, IRCTXT_CHANMODE_CHANGE, channel->name, mode, channel->name); out: g_free(mode); } struct cycle_data { XMPP_SERVER_REC *server; char *joindata; }; static int cycle_join(struct cycle_data *cd) { if (IS_XMPP_SERVER(cd->server)) muc_join(cd->server, cd->joindata, FALSE); g_free(cd->joindata); free(cd); return FALSE; } /* SYNTAX: CYCLE [] */ static void cmd_cycle(const char *data, SERVER_REC *server, WI_ITEM_REC *item) { MUC_REC *channel; char *channame, *reason, *joindata; struct cycle_data *cd; void *free_arg; g_return_if_fail(data != NULL); CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST, item, &channame, &reason)) return; if (*channame == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); if ((channel = muc_find(server, channame)) == NULL) cmd_param_error(CMDERR_NOT_JOINED); joindata = channel->get_join_data(CHANNEL(channel)); window_bind_add(window_item_window(channel), channel->server->tag, channel->name); muc_part(channel, reason); if ((cd = malloc(sizeof(struct cycle_data))) != NULL) { cd->server = XMPP_SERVER(server); cd->joindata = joindata; g_timeout_add(1000, (GSourceFunc)cycle_join, cd); } else { muc_join(XMPP_SERVER(server), joindata, FALSE); free(joindata); } cmd_params_free(free_arg); signal_stop(); } void fe_muc_init(void) { signal_add("xmpp invite", sig_invite); signal_add("xmpp muc joinerror", sig_joinerror); signal_add("message xmpp muc nick", sig_nick); signal_add("message xmpp muc own_nick", sig_own_nick); signal_add("message xmpp muc nick in use", sig_nick_in_use); signal_add("message xmpp muc mode", sig_mode); signal_add_first("command cycle", cmd_cycle); } void fe_muc_deinit(void) { signal_remove("xmpp invite", sig_invite); signal_remove("xmpp muc joinerror", sig_joinerror); signal_remove("message xmpp muc nick", sig_nick); signal_remove("message xmpp muc own_nick", sig_own_nick); signal_remove("message xmpp muc nick in use", sig_nick_in_use); signal_remove("message xmpp muc mode", sig_mode); signal_remove("command cycle", cmd_cycle); } src/fe-common/xep/fe-version.c0000644000175000017500000000376412261362415014360 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "levels.h" #include "printtext.h" #include "signals.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "../module-formats.h" static void sig_version(XMPP_SERVER_REC *server, const char *jid, const char *client, const char *version, const char *os) { XMPP_ROSTER_USER_REC *user; char *name, *str; g_return_if_fail(jid != NULL); if (client == NULL && version == NULL && os == NULL) return; str = g_strconcat("is running ", client != NULL ? client : "", client != NULL && version != NULL ? " " : "", version != NULL ? version : "", (client != NULL || version != NULL) && os != NULL ? " - " : "", os != NULL ? "on " : "", os != NULL ? os : "", (void *)NULL); user = rosters_find_user(server->roster, jid, NULL, NULL); name = user != NULL && user->name != NULL ? format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_NAME, user->name, jid) : format_get_text(MODULE_NAME, NULL, server, NULL, XMPPTXT_FORMAT_JID, jid); printformat_module(MODULE_NAME, server, jid, MSGLEVEL_CRAP, XMPPTXT_MESSAGE_EVENT, name, str); g_free(name); g_free(str); } void fe_version_init(void) { signal_add("xmpp version", sig_version); } void fe_version_deinit(void) { signal_remove("xmpp version", sig_version); } src/fe-common/xep/fe-xep.c0000644000175000017500000000232512261362415013457 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "fe-composing.h" #include "fe-delay.h" #include "fe-muc.h" #include "fe-ping.h" #include "fe-registration.h" #include "fe-vcard.h" #include "fe-version.h" void fe_xep_init(void) { fe_composing_init(); fe_delay_init(); fe_muc_init(); fe_ping_init(); fe_registration_init(); fe_vcard_init(); fe_version_init(); } void fe_xep_deinit(void) { fe_composing_deinit(); fe_delay_deinit(); fe_muc_deinit(); fe_ping_deinit(); fe_registration_deinit(); fe_vcard_deinit(); fe_version_deinit(); } src/fe-common/xep/fe-delay.h0000644000175000017500000000020312261362415013757 0ustar fsfs#ifndef __FE_DELAY_H #define __FE_DELAY_H __BEGIN_DECLS void fe_delay_init(void); void fe_delay_deinit(void); __END_DECLS #endif src/fe-common/xep/fe-registration.c0000644000175000017500000000520412261362415015374 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "ignore.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "signals.h" #include "fe-common/core/module-formats.h" #include "fe-common/irc/module-formats.h" #include "xmpp-servers.h" #include "xep/registration.h" static void sig_failed(const char *username, const char *domain, gpointer error) { char *reason; switch(GPOINTER_TO_INT(error)) { case REGISTRATION_ERROR_UNAUTHORIZED: case REGISTRATION_ERROR_UNAUTHORIZED_REG: reason = "Registration unauthorized"; break; case REGISTRATION_ERROR_UNIMPLEMENTED: case REGISTRATION_ERROR_UNAVAILABLE: reason = "Service unavailable"; break; case REGISTRATION_ERROR_CONFLICT: reason = "Account already exists"; break; case REGISTRATION_ERROR_TIMEOUT: case REGISTRATION_ERROR_TIMEOUT_SERVER: reason = "Connection times out"; break; case REGISTRATION_ERROR_CONNECTION: reason = "Cannot open connection"; break; case REGISTRATION_ERROR_INFO: reason = "Cannot send registration information"; break; default: reason = "Cannot register account"; } printformat_module(MODULE_NAME, NULL, NULL, MSGLEVEL_CRAP, XMPPTXT_REGISTRATION_FAILED, username, domain, reason); } static void sig_succeed(const char *username, const char *domain) { printformat_module(MODULE_NAME, NULL, NULL, MSGLEVEL_CRAP, XMPPTXT_REGISTRATION_SUCCEED, username, domain); } static void sig_started(const char *username, const char *domain) { printformat_module(MODULE_NAME, NULL, NULL, MSGLEVEL_CRAP, XMPPTXT_REGISTRATION_STARTED, username, domain); } void fe_registration_init(void) { signal_add("xmpp registration failed", sig_failed); signal_add("xmpp registration succeed", sig_succeed); signal_add("xmpp registration started", sig_started); } void fe_registration_deinit(void) { signal_remove("xmpp registration failed", sig_failed); signal_remove("xmpp registration succeed", sig_succeed); signal_remove("xmpp registration started", sig_started); } src/fe-common/xep/fe-muc.h0000644000175000017500000000017312261362415013453 0ustar fsfs#ifndef __FE_MUC_H #define __FE_MUC_H __BEGIN_DECLS void fe_muc_init(void); void fe_muc_deinit(void); __END_DECLS #endif src/fe-common/xep/fe-delay.c0000644000175000017500000001157112261362415013764 0ustar fsfs/* * Copyright (C) 2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "settings.h" #include "signals.h" #include "window-items.h" #include "fe-messages.h" #include "fe-queries.h" #include "fe-common/core/module-formats.h" #include "fe-common/core/fe-messages.h" #include "fe-common/irc/module-formats.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "xep/muc.h" static void sig_message_delay(SERVER_REC *server, const char *msg, const char *nick, const char *target, time_t *t, gpointer gpointer_type) { void *item; char *text, *freemsg = NULL; char stamp[BUFSIZ]; int level, type; g_return_if_fail(server != NULL); g_return_if_fail(msg != NULL); g_return_if_fail(nick != NULL); g_return_if_fail(target != NULL); type = GPOINTER_TO_INT(gpointer_type); level = MSGLEVEL_NO_ACT | MSGLEVEL_NOHILIGHT | (type == SEND_TARGET_CHANNEL ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS); item = type == SEND_TARGET_CHANNEL ? (void *)get_muc((XMPP_SERVER_REC *)server, target) : query_find(server, nick); if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis(item, msg); /* MUC */ if (type == SEND_TARGET_CHANNEL) { CHANNEL_REC *chanrec = item; int print_channel; char *nickmode; print_channel = chanrec == NULL || !window_item_is_active((WI_ITEM_REC *)chanrec); if (!print_channel && settings_get_bool("print_active_channel") && window_item_window((WI_ITEM_REC *)chanrec)->items->next != NULL) print_channel = TRUE; nickmode = channel_get_nickmode(chanrec, nick); text = !print_channel ? format_get_text(CORE_MODULE_NAME, NULL, server, target, TXT_PUBMSG, nick, msg, nickmode) : format_get_text(CORE_MODULE_NAME, NULL, server, target, TXT_PUBMSG_CHANNEL, nick, target, msg, nickmode); g_free(nickmode); /* General */ } else text = format_get_text(CORE_MODULE_NAME, NULL, server, target, item == NULL ? TXT_MSG_PRIVATE : TXT_MSG_PRIVATE_QUERY, nick, nick, msg); if (strftime(stamp, sizeof(stamp)-1, settings_get_str("xmpp_timestamp_format"), localtime(t)) == 0) stamp[sizeof(stamp)-1] = '\0'; printformat_module(MODULE_NAME, server, target, level, XMPPTXT_MESSAGE_TIMESTAMP, stamp, text); g_free_not_null(freemsg); g_free(text); } static void sig_message_delay_action(SERVER_REC *server, const char *msg, const char *nick, const char *target, time_t *t, gpointer gpointer_type) { void *item; char *text, *freemsg = NULL; char stamp[BUFSIZ]; int level, type; g_return_if_fail(server != NULL); g_return_if_fail(msg != NULL); g_return_if_fail(nick != NULL); g_return_if_fail(target != NULL); type = GPOINTER_TO_INT(gpointer_type); level = MSGLEVEL_ACTIONS | MSGLEVEL_NO_ACT | MSGLEVEL_NOHILIGHT | (type == SEND_TARGET_CHANNEL ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS); item = type == SEND_TARGET_CHANNEL ? (void *)get_muc((XMPP_SERVER_REC *)server, target) : query_find(server, nick); if (settings_get_bool("emphasis")) msg = freemsg = expand_emphasis(item, msg); /* MUC */ if (type == SEND_TARGET_CHANNEL) { if (item && window_item_is_active(item)) text = format_get_text(IRC_MODULE_NAME, NULL, server, target, IRCTXT_ACTION_PUBLIC, nick, msg); else text = format_get_text(IRC_MODULE_NAME, NULL, server, target, IRCTXT_ACTION_PUBLIC_CHANNEL, nick, target, msg); /* General */ } else text = format_get_text(IRC_MODULE_NAME, NULL, server, nick, (item == NULL) ? IRCTXT_ACTION_PRIVATE : IRCTXT_ACTION_PRIVATE_QUERY, nick, nick, msg); if (strftime(stamp, sizeof(stamp)-1, settings_get_str("xmpp_timestamp_format"), localtime(t)) == 0) stamp[sizeof(stamp)-1] = '\0'; printformat_module(MODULE_NAME, server, target, level, XMPPTXT_MESSAGE_TIMESTAMP, stamp, text); g_free(freemsg); } void fe_delay_init(void) { settings_add_str("xmpp_lookandfeel", "xmpp_timestamp_format", "%Y-%m-%d %H:%M"); signal_add("message xmpp delay", sig_message_delay); signal_add("message xmpp delay action", sig_message_delay_action); } void fe_delay_deinit(void) { signal_remove("message xmpp delay", sig_message_delay); signal_remove("message xmpp delay action", sig_message_delay_action); } src/fe-common/xep/fe-xep.h0000644000175000017500000000017312261362415013463 0ustar fsfs#ifndef __FE_XEP_H #define __FE_XEP_H __BEGIN_DECLS void fe_xep_init(void); void fe_xep_deinit(void); __END_DECLS #endif src/fe-common/xep/fe-composing.h0000644000175000017500000000022312261362415014661 0ustar fsfs#ifndef __FE_COMPOSING_H #define __FE_COMPOSING_H __BEGIN_DECLS void fe_composing_init(void); void fe_composing_deinit(void); __END_DECLS #endif src/fe-common/xep/fe-composing.c0000644000175000017500000001136512261362415014665 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "settings.h" #include "signals.h" #include "special-vars.h" #include "window-items.h" #include "xmpp-servers.h" #include "xmpp-queries.h" #include "tools.h" #define KEY_TAB 9 #define KEY_RETURN 10 #define KEY_ESCAPE 27 #define KEYS_PAGE 91 #define KEYS_OTHER 126 #define KEY_BACKSPACE 127 #define COMPOSING_TIMEOUT 5 static gboolean keylog_active; static int last_key; #define IS_ALIVE_SERVER(server) \ ((server) != NULL \ && g_slist_find(servers, (server)) != NULL \ && (server)->connected) static gboolean stop_composing(gpointer *user_data) { XMPP_QUERY_REC *query = XMPP_QUERY(user_data); if (query == NULL || query->composing_time == 0 || !IS_ALIVE_SERVER(query->server)) return FALSE; /* still composing */ if ((time(NULL) - query->composing_time) < COMPOSING_TIMEOUT) return TRUE; signal_emit("xmpp composing stop", 2, query->server, query->name); query->composing_time = 0; return FALSE; } static void sig_gui_key_pressed(int key) { XMPP_QUERY_REC *query; time_t current_time; char *str = NULL; if (!settings_get_bool("xmpp_send_composing") && keylog_active) return; query = XMPP_QUERY(active_win->active); if (query == NULL || !IS_XMPP_SERVER(query->server)) return; /* ignore command or empty line */ str = parse_special_string("$L", active_win->active_server, active_win->active, "", NULL, 0); if (str != NULL && (*str == *settings_get_str("cmdchars") || *str == '\0')) goto out; if (key != KEY_TAB && key != KEY_RETURN && last_key != KEY_ESCAPE && key != KEY_ESCAPE && last_key != KEYS_PAGE && key != KEYS_PAGE && key != KEYS_OTHER && key != KEY_BACKSPACE) { current_time = time(NULL); /* start composing */ if (query->composing_time == 0) { query->composing_time = current_time; g_timeout_add(COMPOSING_TIMEOUT * 1000, (GSourceFunc)stop_composing, query); signal_emit("xmpp composing start", 2, query->server, query->name); /* still composing */ } else if ((current_time - query->composing_time) < (COMPOSING_TIMEOUT - 1)) query->composing_time = current_time; } out: /* message sent */ if (key == KEY_RETURN) query->composing_time = 0; last_key = key; g_free(str); } static void keyloger_enabled(gboolean enable) { if (enable && !keylog_active) { signal_add_last("gui key pressed", sig_gui_key_pressed); keylog_active = TRUE; } else if (!enable && keylog_active) { signal_remove("gui key pressed", sig_gui_key_pressed); keylog_active = FALSE; } } static void sig_window_changed(WINDOW_REC *new_window, WINDOW_REC *old_window) { XMPP_SERVER_REC *server; XMPP_QUERY_REC *query; if (!settings_get_bool("xmpp_send_composing") || (server = XMPP_SERVER(active_win->active_server)) == NULL) { keyloger_enabled(FALSE); return; } query = XMPP_QUERY(active_win->active); if (query == NULL || !xmpp_have_resource(query->name)) keyloger_enabled(FALSE); else keyloger_enabled(TRUE); } static void sig_query_destroyed(QUERY_REC *query_destroyed) { XMPP_QUERY_REC *query; query = XMPP_QUERY(query_destroyed); if (query != NULL && query->composing_time != 0 && IS_ALIVE_SERVER(query->server)) signal_emit("xmpp composing stop", 2, query->server, query->name); } static void sig_disconnected(XMPP_SERVER_REC *server) { GSList *tmp; XMPP_QUERY_REC *query; if (!IS_XMPP_SERVER(server)) return; for (tmp = queries; tmp != NULL; tmp = tmp->next) { query = XMPP_QUERY(tmp->data); if (query == NULL) continue; if (query->server == server) g_source_remove_by_user_data(query); } } void fe_composing_init(void) { signal_add_last("window changed", sig_window_changed); signal_add("query destroyed", sig_query_destroyed); signal_add("server disconnected", sig_disconnected); settings_add_bool("xmpp", "xmpp_send_composing", TRUE); keylog_active = FALSE; last_key = 0; } void fe_composing_deinit(void) { signal_remove("window changed", sig_window_changed); signal_remove("query destroyed", sig_query_destroyed); signal_remove("server disconnected", sig_disconnected); keyloger_enabled(FALSE); } src/fe-common/xep/fe-version.h0000644000175000017500000000021312261362415014347 0ustar fsfs#ifndef __FE_VERSION_H #define __FE_VERSION_H __BEGIN_DECLS void fe_version_init(void); void fe_version_deinit(void); __END_DECLS #endif src/fe-common/module.h0000644000175000017500000000027112261357644012777 0ustar fsfs#define MODULE_NAME "fe-common/xmpp" #define CORE_MODULE_NAME "fe-common/core" #define IRC_MODULE_NAME "fe-common/irc" #include "irssi-config.h" #include "common.h" #include "xmpp.h" src/fe-common/xmpp-completion.c0000644000175000017500000003106412261362415014634 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "channels.h" #include "channels-setup.h" #include "misc.h" #include "settings.h" #include "signals.h" #include "window-items.h" #include "xmpp-servers.h" #include "xmpp-commands.h" #include "rosters-tools.h" #include "tools.h" static char * quoted_if_space(const char *name, const char *res) { if (res != NULL) return g_utf8_strchr(res, -1, ' ') == NULL ? g_strconcat(name, "/", res, (void *)NULL) : g_strconcat("\"", name, "/", res, "\"", (void *)NULL); else return g_utf8_strchr(name, -1, ' ') == NULL ? g_strdup(name) : g_strconcat("\"", name, "\"", (void *)NULL); } static GList * get_resources(XMPP_SERVER_REC *server, const char *nick, const char *resource_name, gboolean quoted) { GSList *rl; GList *list; XMPP_ROSTER_USER_REC *user; XMPP_ROSTER_RESOURCE_REC *resource; size_t len; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); g_return_val_if_fail(nick != NULL, NULL); len = resource_name != NULL ? strlen(resource_name) : 0; list = NULL; user = rosters_find_user(server->roster, nick, NULL, NULL); if (user == NULL) return NULL; for(rl = user->resources; rl != NULL; rl = rl->next) { resource = rl->data; if (resource_name == NULL || g_ascii_strncasecmp(resource->name, resource_name, len) == 0) list = g_list_append(list, quoted ? quoted_if_space(nick, resource->name) : g_strconcat(nick, "/", resource->name, (void *)NULL)); } return list; } static GList * get_jids(XMPP_SERVER_REC *server, const char *jid) { GSList *gl, *ul; GList *list, *list_case, *offlist, *offlist_case; XMPP_ROSTER_USER_REC *user; int len; list = list_case = offlist = offlist_case = NULL; len = strlen(jid); for (gl = server->roster; gl != NULL; gl = gl->next) { for (ul = ((XMPP_ROSTER_GROUP_REC *)gl->data)->users; ul != NULL ; ul = ul->next) { user = (XMPP_ROSTER_USER_REC *)ul->data; if (strncmp(user->jid, jid, len) == 0) { if (user->resources != NULL) list = g_list_append(list, g_strdup(user->jid)); else offlist = g_list_append(offlist, g_strdup(user->jid)); } else if (g_ascii_strncasecmp(user->jid, jid, len) == 0) { if (user->resources != NULL) list_case = g_list_append(list_case, g_strdup(user->jid)); else offlist_case = g_list_append(offlist_case, g_strdup(user->jid)); } } } /* TODO: temporary list of jids */ list = g_list_concat(list, list_case); list = g_list_concat(list, offlist); list = g_list_concat(list, offlist_case); return list; } static GList * get_nicks(XMPP_SERVER_REC *server, const char *nick, gboolean quoted, gboolean complete_names) { GSList *gl, *ul; GList *list; XMPP_ROSTER_USER_REC *user; char *jid, *resource; int len; gboolean pass2; len = strlen(nick); /* resources completion */ resource = xmpp_extract_resource(nick); if (resource != NULL) { jid = xmpp_strip_resource(nick); list = get_resources(server, jid, resource, quoted); g_free(resource); g_free(jid); return list; } list = NULL; pass2 = FALSE; again: /* first complete with online contacts * then complete with offline contacts */ for (gl = server->roster; gl != NULL; gl = gl->next) { for (ul = ((XMPP_ROSTER_GROUP_REC *)gl->data)->users; ul != NULL ; ul = ul->next) { user = (XMPP_ROSTER_USER_REC *)ul->data; if ((!pass2 && user->resources == NULL) || (pass2 && user->resources != NULL)) continue; if (complete_names && user->name != NULL && g_ascii_strncasecmp(user->name, nick, len) == 0) list = g_list_prepend(list, quoted ? quoted_if_space(user->name, NULL) : g_strdup(user->name)); if (g_ascii_strncasecmp(user->jid, nick, len) == 0) list = g_list_prepend(list, quoted ? quoted_if_space(user->jid, NULL) : g_strdup(user->jid)); } } if ((pass2 = !pass2)) goto again; /* TODO: rewrite this function */ return list; } static void sig_complete_word(GList **list, WINDOW_REC *window, const char *word, const char *linestart, int *want_space) { XMPP_SERVER_REC *server; g_return_if_fail(list != NULL); g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); if ((server = XMPP_SERVER(window->active_server)) == NULL) return; if (g_ascii_strncasecmp(linestart, settings_get_str("cmdchars"), 1) == 0) { *list = g_list_concat(*list, get_nicks(server, *word == '"' ? word+1 : word , TRUE, TRUE)); } else if (!IS_CHANNEL(window->active)) *list = g_list_concat(*list, get_nicks(server, word, FALSE, TRUE)); } static void sig_complete_command_roster_group(GList **list, WINDOW_REC *window, const char *word, const char *args, int *want_space) { GSList *gl; XMPP_SERVER_REC *server; XMPP_ROSTER_GROUP_REC *group; int len; char **tmp; g_return_if_fail(list != NULL); g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); g_return_if_fail(args != NULL); server = XMPP_SERVER(window->active_server); if (server == NULL) return; len = strlen(word); tmp = g_strsplit(args, " ", 2); /* complete nicks */ if (tmp[0] == NULL) *list = g_list_concat(*list, get_nicks(server, *word == '"' ? word+1 : word , TRUE, FALSE)); /* complete groups */ else if (tmp[0] != NULL && tmp[1] == NULL) { for (gl = server->roster; gl != NULL; gl = gl->next) { group = (XMPP_ROSTER_GROUP_REC *)gl->data; if (group->name != NULL && g_ascii_strncasecmp(word, group->name, len) == 0) *list = g_list_append(*list, g_strdup(group->name)); } } g_strfreev(tmp); if (*list != NULL) signal_stop(); } static void sig_complete_command_roster_others(GList **list, WINDOW_REC *window, const char *word, const char *args, int *want_space) { XMPP_SERVER_REC *server; char **tmp; g_return_if_fail(list != NULL); g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); g_return_if_fail(args != NULL); if ((server = XMPP_SERVER(window->active_server)) == NULL) return; tmp = g_strsplit(args, " ", 2); /* complete nicks */ if (tmp[0] == NULL) *list = g_list_concat(*list, get_nicks(server, *word == '"' ? word+1 : word , TRUE, FALSE)); g_strfreev(tmp); if (*list != NULL) signal_stop(); } static void sig_complete_command_presence(GList **list, WINDOW_REC *window, const char *word, const char *args, int *want_space) { XMPP_SERVER_REC *server; char **tmp; g_return_if_fail(list != NULL); g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); g_return_if_fail(args != NULL); if ((server = XMPP_SERVER(window->active_server)) == NULL) return; tmp = g_strsplit(args, " ", 2); /* complete nicks */ if (tmp[0] == NULL) *list = g_list_concat(*list, get_jids(server, *word == '"' ? word+1 : word)); g_strfreev(tmp); if (*list != NULL) signal_stop(); } static GList * get_channels(XMPP_SERVER_REC *server, const char *word) { GSList *tmp; GList *list; CHANNEL_REC *channel; CHANNEL_SETUP_REC *channel_setup; int len; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); g_return_val_if_fail(word != NULL, NULL); len = strlen(word); list = NULL; for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { channel = CHANNEL(tmp->data); if (channel != NULL && g_ascii_strncasecmp(channel->name, word, len) == 0) list = g_list_append(list, g_strdup(channel->name)); } for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) { channel_setup = tmp->data; if ((PROTO_CHECK_CAST(channel_setup, CHANNEL_SETUP_REC, chat_type, XMPP_PROTOCOL_NAME) || *channel_setup->name != '#') && g_ascii_strncasecmp(channel_setup->name, word, len) == 0 && glist_find_string(list, channel_setup->name) == NULL) list = g_list_append(list, g_strdup(channel_setup->name)); } return list; } static void sig_complete_command_channels(GList **list, WINDOW_REC *window, const char *word, const char *args, int *want_space) { XMPP_SERVER_REC *server; g_return_if_fail(list != NULL); g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); server = XMPP_SERVER(window->active_server); if (server == NULL) return; *list = get_channels(server, word); if (*list != NULL) signal_stop(); } static void sig_complete_command_invite(GList **list, WINDOW_REC *window, const char *word, const char *args, int *want_space) { XMPP_SERVER_REC *server; char **tmp; g_return_if_fail(list != NULL); g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); server = XMPP_SERVER(window->active_server); if (server == NULL) return; /* complete channels */ tmp = g_strsplit(args, " ", 2); if (tmp[0] != NULL && tmp[1] == NULL) *list = get_channels(server, word); g_strfreev(tmp); if (*list != NULL) signal_stop(); } static void sig_complete_command_away(GList **list, WINDOW_REC *window, const char *word, const char *args, int *want_space) { XMPP_SERVER_REC *server; int len; g_return_if_fail(list != NULL); g_return_if_fail(window != NULL); g_return_if_fail(word != NULL); server = XMPP_SERVER(window->active_server); if (server == NULL) return; len = strlen(word); if (g_ascii_strncasecmp(word, xmpp_presence_show[XMPP_PRESENCE_AWAY], len) == 0) *list = g_list_append(*list, g_strdup(xmpp_presence_show[XMPP_PRESENCE_AWAY])); if (g_ascii_strncasecmp(word, xmpp_presence_show[XMPP_PRESENCE_XA], len) == 0) *list = g_list_append(*list, g_strdup(xmpp_presence_show[XMPP_PRESENCE_XA])); if (g_ascii_strncasecmp(word, xmpp_presence_show[XMPP_PRESENCE_DND], len) == 0) *list = g_list_append(*list, g_strdup(xmpp_presence_show[XMPP_PRESENCE_DND])); if (g_ascii_strncasecmp(word, xmpp_presence_show[XMPP_PRESENCE_CHAT], len) == 0) *list = g_list_append(*list, g_strdup(xmpp_presence_show[XMPP_PRESENCE_CHAT])); if (g_ascii_strncasecmp(word, xmpp_presence_show[XMPP_PRESENCE_ONLINE], len) == 0) *list = g_list_append(*list, g_strdup("online")); signal_stop(); } void xmpp_completion_init(void) { signal_add("complete word", sig_complete_word); signal_add("complete command roster group", sig_complete_command_roster_group); signal_add("complete command roster add", sig_complete_command_roster_others); signal_add("complete command roster remove", sig_complete_command_roster_others); signal_add("complete command roster name", sig_complete_command_roster_others); signal_add("complete command presence accept", sig_complete_command_presence); signal_add("complete command presence deny", sig_complete_command_presence); signal_add("complete command presence subscribe", sig_complete_command_presence); signal_add("complete command presence unsubscribe", sig_complete_command_presence); signal_add("complete command join", sig_complete_command_channels); signal_add("complete command part", sig_complete_command_channels); signal_add("complete command invite", sig_complete_command_invite); signal_add("complete command away", sig_complete_command_away); } void xmpp_completion_deinit(void) { signal_remove("complete word", sig_complete_word); signal_remove("complete command roster group", sig_complete_command_roster_group); signal_remove("complete command roster add", sig_complete_command_roster_others); signal_remove("complete command roster remove", sig_complete_command_roster_others); signal_remove("complete command roster name", sig_complete_command_roster_others); signal_remove("complete command presence accept", sig_complete_command_presence); signal_remove("complete command presence deny", sig_complete_command_presence); signal_remove("complete command presence subscribe", sig_complete_command_presence); signal_remove("complete command presence unsubscribe", sig_complete_command_presence); signal_remove("complete command join", sig_complete_command_channels); signal_remove("complete command part", sig_complete_command_channels); signal_remove("complete command invite", sig_complete_command_invite); signal_remove("complete command away", sig_complete_command_away); } src/fe-common/fe-stanzas.c0000644000175000017500000000551412261362415013555 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "levels.h" #include "module-formats.h" #include "printtext.h" #include "settings.h" #include "signals.h" #include "window-items.h" #include "xmpp-servers.h" static WINDOW_REC * get_console(XMPP_SERVER_REC *server) { WINDOW_REC *window; char *name; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); name = g_strconcat("(raw:", (server->connrec->chatnet == NULL || *server->connrec->chatnet == '\0') ? server->jid : server->connrec->chatnet, ")", (void *)NULL); if ((window = window_find_name(name)) == NULL) { window = window_create(NULL, TRUE); window_set_name(window, name); window_change_server(window, server); } g_free(name); return window; } static void sig_xml_in(XMPP_SERVER_REC *server, const char *msg) { WINDOW_REC *window; char *len; if (!settings_get_bool("xmpp_xml_console")) return; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(msg != NULL); if ((window = get_console(server)) != NULL) { len = g_strdup_printf("%lu", (unsigned long)strlen(msg)); printformat_module_window(MODULE_NAME, window, MSGLEVEL_CRAP, XMPPTXT_RAW_IN_HEADER, len); g_free(len); printformat_module_window(MODULE_NAME, window, MSGLEVEL_CRAP, XMPPTXT_RAW_MESSAGE, msg); } } static void sig_xml_out(XMPP_SERVER_REC *server, const char *msg) { WINDOW_REC *window; char *len; if (!settings_get_bool("xmpp_xml_console")) return; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(msg != NULL); if ((window = get_console(server)) != NULL) { len = g_strdup_printf("%lu", (unsigned long)strlen(msg)); printformat_module_window(MODULE_NAME, window, MSGLEVEL_CRAP, XMPPTXT_RAW_OUT_HEADER, len); g_free(len); printformat_module_window(MODULE_NAME, window, MSGLEVEL_CRAP, XMPPTXT_RAW_MESSAGE, msg); } } void fe_stanzas_init(void) { signal_add("xmpp xml in", (SIGNAL_FUNC)sig_xml_in); signal_add("xmpp xml out", (SIGNAL_FUNC)sig_xml_out); settings_add_bool("xmpp_lookandfeel", "xmpp_xml_console", FALSE); } void fe_stanzas_deinit(void) { signal_remove("xmpp xml in", (SIGNAL_FUNC)sig_xml_in); signal_remove("xmpp xml out", (SIGNAL_FUNC)sig_xml_out); } src/Makefile0000644000175000017500000000035412261362415011113 0ustar fsfsall clean user-install install: @echo "core module:" @cd core/ && ${MAKE} $@ @echo "fe-common submodule:" @cd fe-common/ && ${MAKE} $@ @echo "fe-text submodule:" @cd fe-text/ && ${MAKE} $@ .PHONY: all clean user-install install src/rules.mk0000644000175000017500000000132212261362415011132 0ustar fsfsinclude ../../config.mk OBJS = ${SRCS:.c=.o} LIBSO=lib${LIB}.so all: ${LIBSO} .c.o: ${CC} ${CFLAGS} ${INCS} -o $@ -c $< ${LIBSO}: ${OBJS} ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} clean: rm -f ${LIBSO} ${OBJS} install: all @echo installing the module ${LIBSO} to ${DESTDIR}${IRSSI_LIB}/modules install -d ${DESTDIR}${IRSSI_LIB}/modules install ${LIBSO} ${DESTDIR}${IRSSI_LIB}/modules uninstall: @echo deinstalling the module ${LIBSO} from ${DESTDIR}${IRSSI_LIB}/modules rm -f ${DESTDIR}${IRSSI_LIB}/modules/${LIBSO} user-install: env DESTDIR= IRSSI_LIB=~/.irssi ${MAKE} install user-uninstall: env DESTDIR= IRSSI_LIB=~/.irssi ${MAKE} uninstall .PHONY: clean install uninstall user-install user-uninstall src/fe-text/0000755000175000017500000000000012261362415011025 5ustar fsfssrc/fe-text/Makefile0000644000175000017500000000033112261362415012462 0ustar fsfsLIB= text_xmpp SRCS= text-xmpp-core.c \ xep/text-composing.c \ xep/text-muc.c \ xep/text-xep.c LIB_INCS = -I../../src/fe-text/include/irssi/src/fe-text LIB_LIBS = `pkg-config --libs glib-2.0` include ../rules.mk src/fe-text/xep/0000755000175000017500000000000012261362415011621 5ustar fsfssrc/fe-text/xep/text-xep.c0000644000175000017500000000162712261362415013551 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "text-composing.h" #include "text-muc.h" void text_xep_init(void) { text_composing_init(); text_muc_init(); } void text_xep_deinit(void) { text_composing_deinit(); text_muc_deinit(); } src/fe-text/xep/text-muc.c0000644000175000017500000000610512261362415013535 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "settings.h" #include "signals.h" #include "statusbar-item.h" #include "window-items.h" #include "xmpp-servers.h" #include "xep/muc.h" static void update_nick_statusbar(XMPP_SERVER_REC *server, MUC_REC *channel, gboolean redraw) { char *newnick; newnick = IS_MUC(channel) ? channel->nick : settings_get_bool("xmpp_set_nick_as_username") ? server->user : server->jid; if (strcmp(server->nick, newnick) == 0) return; g_free(server->nick); server->nick = g_strdup(newnick); if (redraw) statusbar_items_redraw("user"); } static void sig_window_changed(WINDOW_REC *window, WINDOW_REC *oldwindow) { XMPP_SERVER_REC *server; g_return_if_fail(window != NULL); if ((server = XMPP_SERVER(window->active_server)) == NULL) return; update_nick_statusbar(server, MUC(window->active), FALSE); } static void sig_window_destroyed(WINDOW_REC *window) { XMPP_SERVER_REC *server; MUC_REC *channel; g_return_if_fail(window != NULL); if ((server = XMPP_SERVER(window->active_server)) == NULL) return; channel = MUC(window->active); if (channel != NULL || !IS_MUC(active_win->active)) update_nick_statusbar(server, NULL, TRUE); } static void sig_nick_changed(MUC_REC *channel) { if (!IS_MUC(channel)) return; if (MUC(active_win->active) == channel) update_nick_statusbar(channel->server, channel, TRUE); } static void sig_channel_joined(MUC_REC *channel) { g_return_if_fail(channel != NULL); if (!IS_MUC(channel)) return; if (MUC(active_win->active) == channel) update_nick_statusbar(channel->server, channel, TRUE); } static void sig_channel_destroyed(MUC_REC *channel) { g_return_if_fail(channel != NULL); if (!IS_MUC(channel)) return; if (MUC(active_win->active) == channel) update_nick_statusbar(channel->server, NULL, TRUE); } void text_muc_init(void) { signal_add("window changed", sig_window_changed); signal_add("window destroyed", sig_window_destroyed); signal_add("message xmpp channel own_nick", sig_nick_changed); signal_add("channel joined", sig_channel_joined); signal_add("channel destroyed", sig_channel_destroyed); } void text_muc_deinit(void) { signal_remove("window changed", sig_window_changed); signal_remove("window destroyed", sig_window_destroyed); signal_remove("message xmpp channel own_nick", sig_nick_changed); signal_remove("channel joined", sig_channel_joined); signal_remove("channel destroyed", sig_channel_destroyed); } src/fe-text/xep/text-muc.h0000644000175000017500000000020312261362415013533 0ustar fsfs#ifndef __TEXT_MUC_H #define __TEXT_MUC_H __BEGIN_DECLS void text_muc_init(void); void text_muc_deinit(void); __END_DECLS #endif src/fe-text/xep/text-composing.c0000644000175000017500000000513112261362415014745 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "module-formats.h" #include "signals.h" #include "statusbar-item.h" #include "window-items.h" #include "xmpp-servers.h" #include "xmpp-queries.h" static void item_xmpp_composing(struct SBAR_ITEM_REC *item, int get_size_only) { XMPP_SERVER_REC *server; XMPP_QUERY_REC *query; char *str = NULL; server = XMPP_SERVER(active_win->active_server); if (server == NULL || !IS_XMPP_SERVER(server)) goto out; query = XMPP_QUERY(active_win->active); if (query == NULL) goto out; if (query->composing_visible) str = "{sb composing}"; out: if (str == NULL) { if (get_size_only) statusbar_item_set_size(item, 0, 0); return; } statusbar_item_default_handler(item, get_size_only, str, "", FALSE); } static void xmpp_composing_update(void) { statusbar_items_redraw("xmpp_composing"); } static void event_message_sent(XMPP_SERVER_REC *server, const char *message, const char *full_jid, const char *ignore) { XMPP_QUERY_REC *query; if (!IS_XMPP_SERVER(server)) return; query = xmpp_query_find(server, full_jid); if (query != NULL) query->composing_visible = FALSE; xmpp_composing_update(); } void text_composing_init(void) { statusbar_item_register("xmpp_composing", NULL, item_xmpp_composing); signal_add("window changed", xmpp_composing_update); signal_add_last("xmpp composing show", xmpp_composing_update); signal_add_last("xmpp composing hide", xmpp_composing_update); signal_add("message private", event_message_sent); signal_add("message xmpp action", event_message_sent); } void text_composing_deinit(void) { statusbar_item_unregister("xmpp_composing"); signal_remove("window changed", xmpp_composing_update); signal_remove("xmpp composing show", xmpp_composing_update); signal_remove("xmpp composing hide", xmpp_composing_update); signal_remove("message private", event_message_sent); signal_remove("message xmpp action", event_message_sent); } src/fe-text/xep/text-xep.h0000644000175000017500000000020312261362415013543 0ustar fsfs#ifndef __TEXT_XEP_H #define __TEXT_XEP_H __BEGIN_DECLS void text_xep_init(void); void text_xep_deinit(void); __END_DECLS #endif src/fe-text/xep/text-composing.h0000644000175000017500000000023312261362415014750 0ustar fsfs#ifndef __TEXT_COMPOSING_H #define __TEXT_COMPOSING_H __BEGIN_DECLS void text_composing_init(void); void text_composing_deinit(void); __END_DECLS #endif src/fe-text/module.h0000644000175000017500000000014112261357644012467 0ustar fsfs#define MODULE_NAME "xmpp/text" #include "irssi-config.h" #include "common.h" #include "xmpp.h" src/fe-text/text-xmpp-core.c0000644000175000017500000000160712261362415014071 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "modules.h" #include "xep/text-xep.h" void text_xmpp_init(void) { text_xep_init(); module_register("xmpp", "text"); } void text_xmpp_deinit(void) { text_xep_deinit(); } src/core/0000755000175000017500000000000012261362415010401 5ustar fsfssrc/core/loudmouth-tools.h0000644000175000017500000000027212261362415013731 0ustar fsfs#ifndef __LOUDMOUTH_TOOLS_H #define __LOUDMOUTH_TOOLS_H __BEGIN_DECLS LmMessageNode *lm_find_node(LmMessageNode *, const char *, const char *, const char *); __END_DECLS #endif src/core/stanzas.c0000644000175000017500000001025712261362415012235 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "settings.h" #include "signals.h" #include "xmpp-servers.h" #include "tools.h" static int message_types[] = { LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_TYPE_IQ, -1 }; static void send_stanza(XMPP_SERVER_REC *server, LmMessage *lmsg) { char *xml, *recoded; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(lmsg != NULL); xml = lm_message_node_to_string(lmsg->node); recoded = xmpp_recode_in(xml); g_free(xml); signal_emit("xmpp xml out", 2, server, recoded); g_free(recoded); lm_connection_send(server->lmconn, lmsg, NULL); } static LmHandlerResult handle_stanza(LmMessageHandler *handler, LmConnection *connection, LmMessage *lmsg, gpointer user_data) { XMPP_SERVER_REC *server; int type; const char *id; char *from, *to, *raw; if ((server = XMPP_SERVER(user_data)) == NULL) return LM_HANDLER_RESULT_REMOVE_MESSAGE; raw = xmpp_recode_in(lm_message_node_to_string(lmsg->node)); signal_emit("xmpp xml in", 2, server, raw); g_free(raw); type = lm_message_get_sub_type(lmsg); id = lm_message_node_get_attribute(lmsg->node, "id"); if (id == NULL) id = ""; from = xmpp_recode_in(lm_message_node_get_attribute(lmsg->node, "from")); if (from == NULL) from = g_strdup(""); to = xmpp_recode_in(lm_message_node_get_attribute(lmsg->node, "to")); if (to == NULL) to = g_strdup(""); switch(lm_message_get_type(lmsg)) { case LM_MESSAGE_TYPE_MESSAGE: signal_emit("xmpp recv message", 6, server, lmsg, type, id, from, to); break; case LM_MESSAGE_TYPE_PRESENCE: signal_emit("xmpp recv presence", 6, server, lmsg, type, id, from, to); break; case LM_MESSAGE_TYPE_IQ: signal_emit("xmpp recv iq", 6, server, lmsg, type, id, from, to); break; default: signal_emit("xmpp recv others", 6, server, lmsg, type, id, from, to); break; } g_free(from); g_free(to); return LM_HANDLER_RESULT_REMOVE_MESSAGE; } static void unregister_stanzas(XMPP_SERVER_REC *server) { GSList *tmp, *next; if (!IS_XMPP_SERVER(server)) return; for (tmp = server->msg_handlers; tmp != NULL; tmp = next) { next = tmp->next; if (lm_message_handler_is_valid(tmp->data)) lm_message_handler_invalidate(tmp->data); lm_message_handler_unref(tmp->data); server->msg_handlers = g_slist_remove(server->msg_handlers, tmp->data); } } static void register_stanzas(XMPP_SERVER_REC *server) { LmMessageHandler *h; int i; if (!IS_XMPP_SERVER(server)) return; if (server->msg_handlers != NULL && g_slist_length(server->msg_handlers) != 0) unregister_stanzas(server); for(i = 0; message_types[i] != -1; ++i) { h = lm_message_handler_new(handle_stanza, server, NULL); lm_connection_register_message_handler(server->lmconn, h, message_types[i], LM_HANDLER_PRIORITY_NORMAL); server->msg_handlers = g_slist_prepend(server->msg_handlers, h); } } void stanzas_init(void) { signal_add("server connecting", register_stanzas); signal_add_first("server disconnected", unregister_stanzas); signal_add_last("xmpp send message", send_stanza); signal_add_last("xmpp send presence", send_stanza); signal_add_last("xmpp send iq", send_stanza); signal_add_last("xmpp send others", send_stanza); } void stanzas_deinit(void) { signal_remove("server connecting", register_stanzas); signal_remove("server disconnected", unregister_stanzas); signal_remove("xmpp send message", send_stanza); signal_remove("xmpp send presence", send_stanza); signal_remove("xmpp send iq", send_stanza); signal_remove("xmpp send others", send_stanza); } src/core/Makefile0000644000175000017500000000112512261362415012040 0ustar fsfsLIB= xmpp_core SRCS= xmpp-commands.c \ xmpp-core.c \ xmpp-queries.c \ xmpp-servers.c \ xmpp-servers-reconnect.c \ xmpp-settings.c \ loudmouth-tools.c \ protocol.c \ rosters.c \ rosters-tools.c \ stanzas.c \ tools.c \ xep/chatstates.c \ xep/composing.c \ xep/datetime.c \ xep/delay.c \ xep/disco.c \ xep/muc-commands.c \ xep/muc-events.c \ xep/muc-nicklist.c \ xep/muc-reconnect.c \ xep/muc.c \ xep/oob.c \ xep/ping.c \ xep/registration.c \ xep/tool_datalist.c \ xep/vcard.c \ xep/version.c \ xep/xep.c LIB_LIBS = `pkg-config --libs loudmouth-1.0` include ../rules.mk src/core/xmpp-commands.h0000644000175000017500000000307012261362415013335 0ustar fsfs#ifndef __XMPP_COMMANDS_H #define __XMPP_COMMANDS_H #include "commands.h" enum { XMPP_COMMAND_AWAY, XMPP_COMMAND_QUOTE, XMPP_COMMAND_ROSTER, XMPP_COMMAND_WHOIS, XMPP_COMMAND_PRESENCE }; extern const char *xmpp_commands[]; enum { XMPP_COMMAND_ROSTER_PARAM_FULL, XMPP_COMMAND_ROSTER_PARAM_ADD, XMPP_COMMAND_ROSTER_PARAM_REMOVE, XMPP_COMMAND_ROSTER_PARAM_NAME, XMPP_COMMAND_ROSTER_PARAM_GROUP, }; extern const char *xmpp_command_roster[]; enum { XMPP_COMMAND_ROSTER_PARAM_ACCEPT, XMPP_COMMAND_ROSTER_PARAM_DENY, XMPP_COMMAND_ROSTER_PARAM_SUBSCRIBE, XMPP_COMMAND_ROSTER_PARAM_UNSUBSCRIBE, }; extern const char *xmpp_command_presence[]; #define command_bind_xmpp(cmd, section, signal) \ command_bind_proto(cmd, XMPP_PROTOCOL, section, signal) #define command_bind_xmpp_first(cmd, section, signal) \ command_bind_proto_first(cmd, XMPP_PROTOCOL, section, signal) #define command_bind_xmpp_last(cmd, section, signal) \ command_bind_proto_last(cmd, XMPP_PROTOCOL, section, signal) /* Simply returns if server isn't for XMPP protocol. Prints ERR_NOT_CONNECTED * error if there's no server or server isn't connected yet */ #define CMD_XMPP_SERVER(server) \ G_STMT_START { \ if (((server) != NULL) && !IS_XMPP_SERVER(server)) { \ return; \ } \ if (((server) == NULL) || !(server)->connected) { \ cmd_return_error(CMDERR_NOT_CONNECTED); \ } \ } G_STMT_END __BEGIN_DECLS char *xmpp_get_dest(const char *, XMPP_SERVER_REC *, WI_ITEM_REC *); void xmpp_commands_init(void); void xmpp_commands_deinit(void); __END_DECLS #endif src/core/xmpp.h0000644000175000017500000000071112261362415011535 0ustar fsfs#ifndef __XMPP_H #define __XMPP_H typedef struct _XMPP_SERVER_CONNECT_REC XMPP_SERVER_CONNECT_REC; typedef struct _XMPP_SERVER_REC XMPP_SERVER_REC; typedef struct _XMPP_QUERY_REC XMPP_QUERY_REC; typedef struct _XMPP_NICK_REC XMPP_NICK_REC; typedef struct _MUC_REC MUC_REC; #define XMPP_PROTOCOL_NAME "XMPP" #define XMPP_PROTOCOL (chat_protocol_lookup(XMPP_PROTOCOL_NAME)) #define IRSSI_XMPP_PACKAGE "irssi-xmpp" #define IRSSI_XMPP_VERSION "0.52" #endif src/core/tools.h0000644000175000017500000000112312261362415011707 0ustar fsfs#ifndef __TOOLS_H #define __TOOLS_H __BEGIN_DECLS char *xmpp_recode_out(const char *); char *xmpp_recode_in(const char *); char *xmpp_find_resource_sep(const char *); char *xmpp_extract_resource(const char *); char *xmpp_strip_resource(const char *); char *xmpp_extract_user(const char *); char *xmpp_extract_domain(const char *); gboolean xmpp_have_domain(const char *); gboolean xmpp_have_resource(const char *); gboolean xmpp_priority_out_of_bound(const int); gboolean xmpp_presence_changed(const int, const int, const char *, const char *, const int, const int); __END_DECLS #endif src/core/rosters-tools.h0000644000175000017500000000101112261362415013402 0ustar fsfs#ifndef __ROSTER_TOOLS_H #define __ROSTER_TOOLS_H #include "rosters.h" __BEGIN_DECLS XMPP_ROSTER_USER_REC *rosters_find_user(GSList *, const char *, XMPP_ROSTER_GROUP_REC **, XMPP_ROSTER_RESOURCE_REC **); XMPP_ROSTER_RESOURCE_REC *rosters_find_resource(GSList *, const char *); void rosters_reorder(XMPP_ROSTER_GROUP_REC *); char *rosters_resolve_name(XMPP_SERVER_REC *, const char *); char *rosters_get_name(XMPP_SERVER_REC *, const char *); int xmpp_get_show(const char *); __END_DECLS #endif src/core/xmpp-settings.h0000644000175000017500000000022712261362415013375 0ustar fsfs#ifndef __XMPP_SETTINGS_H #define __XMPP_SETTINGS_H __BEGIN_DECLS void xmpp_settings_init(void); void xmpp_settings_deinit(void); __END_DECLS #endif src/core/protocol.c0000644000175000017500000000665112261362415012416 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "signals.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "tools.h" static void sig_set_presence(XMPP_SERVER_REC *server, const int show, const char *status, const int priority) { LmMessage *lmsg; char *str; g_return_if_fail(IS_XMPP_SERVER(server)); if (!xmpp_presence_changed(show, server->show, status, server->away_reason, priority, server->priority)) { signal_stop(); return; } server->show = show; g_free(server->away_reason); server->away_reason = g_strdup(status); if (!xmpp_priority_out_of_bound(priority)) server->priority = priority; lmsg = lm_message_new(NULL, LM_MESSAGE_TYPE_PRESENCE); if (show != XMPP_PRESENCE_AVAILABLE) lm_message_node_add_child(lmsg->node, "show", xmpp_presence_show[server->show]); if (status != NULL) { str = xmpp_recode_out(server->away_reason); lm_message_node_add_child(lmsg->node, "status", str); g_free(str); } str = g_strdup_printf("%d", server->priority); lm_message_node_add_child(lmsg->node, "priority", str); g_free(str); signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); if (show != XMPP_PRESENCE_AVAILABLE) /* away */ signal_emit("event 306", 2, server, server->jid); else if (server->usermode_away) /* unaway */ signal_emit("event 305", 2, server, server->jid); } static void sig_recv_message(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node; char *str, *subject; if ((type != LM_MESSAGE_SUB_TYPE_NOT_SET && type != LM_MESSAGE_SUB_TYPE_HEADLINE && type != LM_MESSAGE_SUB_TYPE_NORMAL && type != LM_MESSAGE_SUB_TYPE_CHAT) || server->ischannel(SERVER(server), from)) return; node = lm_message_node_get_child(lmsg->node, "subject"); if (node != NULL && node->value != NULL && *node->value != '\0') { str = xmpp_recode_in(node->value); subject = g_strconcat("Subject: ", str, (void *)NULL); g_free(str); signal_emit("message private", 4, server, subject, from, from); g_free(subject); } node = lm_message_node_get_child(lmsg->node, "body"); if (node != NULL && node->value != NULL && *node->value != '\0') { str = xmpp_recode_in(node->value); if (g_ascii_strncasecmp(str, "/me ", 4) == 0) signal_emit("message xmpp action", 5, server, str+4, from, from, GINT_TO_POINTER(SEND_TARGET_NICK)); else signal_emit("message private", 4, server, str, from, from); g_free(str); } } void protocol_init(void) { signal_add_first("xmpp set presence", sig_set_presence); signal_add("xmpp recv message", sig_recv_message); } void protocol_deinit(void) { signal_remove("xmpp set presence", sig_set_presence); signal_remove("xmpp recv message", sig_recv_message); } src/core/xmpp-core.c0000644000175000017500000000637212261362415012467 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "signals.h" #include "channels.h" #include "channels-setup.h" #include "chat-protocols.h" #include "chatnets.h" #include "servers-setup.h" #include "settings.h" #include "xmpp-commands.h" #include "xmpp-queries.h" #include "xmpp-servers.h" #include "xmpp-servers-reconnect.h" #include "xmpp-settings.h" #include "protocol.h" #include "rosters.h" #include "stanzas.h" #include "xep/xep.h" static CHATNET_REC * create_chatnet(void) { return g_new0(CHATNET_REC, 1); } static SERVER_SETUP_REC * create_server_setup(void) { return g_new0(SERVER_SETUP_REC, 1); } static SERVER_CONNECT_REC * create_server_connect(void) { XMPP_SERVER_CONNECT_REC *conn; conn = g_new0(XMPP_SERVER_CONNECT_REC, 1); conn->channels_list = NULL; conn->real_jid = NULL; conn->prompted_password = NULL; return (SERVER_CONNECT_REC *)conn; } static CHANNEL_SETUP_REC * create_channel_setup(void) { return g_new0(CHANNEL_SETUP_REC, 1); } static void destroy_server_connect(XMPP_SERVER_CONNECT_REC *conn) { g_free_not_null(conn->real_jid); g_free_not_null(conn->prompted_password); } static CHANNEL_REC * channel_create(SERVER_REC *server, const char *name, const char *visible_name, int automatic) { return g_new0(CHANNEL_REC, 1); } void xmpp_core_init(void) { CHAT_PROTOCOL_REC *rec; rec = g_new0(CHAT_PROTOCOL_REC, 1); rec->name = XMPP_PROTOCOL_NAME; rec->fullname = "XMPP, Extensible messaging and presence protocol"; rec->chatnet = "xmppnet"; rec->case_insensitive = FALSE; rec->create_chatnet = create_chatnet; rec->create_server_setup = create_server_setup; rec->create_server_connect = create_server_connect; rec->create_channel_setup = create_channel_setup; rec->destroy_server_connect = (void (*)(SERVER_CONNECT_REC *))destroy_server_connect; rec->server_init_connect = xmpp_server_init_connect; rec->server_connect = (void (*)(SERVER_REC *))xmpp_server_connect; rec->channel_create = channel_create; rec->query_create = xmpp_query_create; chat_protocol_register(rec); g_free(rec); xmpp_commands_init(); xmpp_servers_init(); xmpp_servers_reconnect_init(); xmpp_settings_init(); protocol_init(); rosters_init(); stanzas_init(); xep_init(); module_register("xmpp", "core"); } void xmpp_core_deinit(void) { xep_deinit(); /* deinit servers first to disconnect servers before unloading */ xmpp_servers_deinit(); xmpp_commands_deinit(); xmpp_servers_reconnect_deinit(); xmpp_settings_deinit(); protocol_deinit(); rosters_deinit(); stanzas_deinit(); signal_emit("chat protocol deinit", 1, chat_protocol_find("XMPP")); chat_protocol_unregister("XMPP"); } src/core/xmpp-servers-reconnect.c0000644000175000017500000000436612261362415015207 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "signals.h" #include "xmpp-servers.h" static void sig_server_connect_copy(SERVER_CONNECT_REC **dest, XMPP_SERVER_CONNECT_REC *src) { XMPP_SERVER_CONNECT_REC *conn; g_return_if_fail(dest != NULL); if (!IS_XMPP_SERVER_CONNECT(src)) return; conn = g_new0(XMPP_SERVER_CONNECT_REC, 1); conn->chat_type = XMPP_PROTOCOL; conn->show = src->show; conn->priority = src->priority; conn->prompted_password = g_strdup(src->prompted_password); g_free(src->nick); src->nick = src->real_jid; src->real_jid = NULL; *dest = (SERVER_CONNECT_REC *)conn; } static void sig_save_status(XMPP_SERVER_CONNECT_REC *conn, XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER_CONNECT(conn) || !IS_XMPP_SERVER(server) || !server->connected) return; conn->show = server->show; conn->priority = server->priority; } static void sig_connected(XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER(server) || !server->connrec->reconnection) return; signal_emit("xmpp set presence", 4, server, server->connrec->show, server->connrec->away_reason, server->connrec->priority); g_free_and_null(server->connrec->away_reason); } void xmpp_servers_reconnect_init(void) { signal_add_first("server connect copy", sig_server_connect_copy); signal_add("server reconnect save status", sig_save_status); signal_add_last("server connected", sig_connected); } void xmpp_servers_reconnect_deinit(void) { signal_remove("server connect copy", sig_server_connect_copy); signal_remove("server reconnect save status", sig_save_status); signal_remove("server connected", sig_connected); } src/core/rosters.h0000644000175000017500000000171112261362415012253 0ustar fsfs#ifndef __ROSTER_H #define __ROSTER_H enum { XMPP_PRESENCE_UNAVAILABLE, XMPP_PRESENCE_ERROR, XMPP_PRESENCE_XA, XMPP_PRESENCE_DND, XMPP_PRESENCE_AWAY, XMPP_PRESENCE_AVAILABLE, XMPP_PRESENCE_CHAT, XMPP_PRESENCE_ONLINE, XMPP_PRESENCE_SHOW_LEN }; extern const char *xmpp_presence_show[]; enum { XMPP_SUBSCRIPTION_REMOVE, XMPP_SUBSCRIPTION_NONE, XMPP_SUBSCRIPTION_TO, XMPP_SUBSCRIPTION_FROM, XMPP_SUBSCRIPTION_BOTH }; extern const char *xmpp_subscription[]; /* roster structure */ typedef struct _XMPP_ROSTER_RESOURCE_REC { char *name; int priority; int show; char *status; char *composing_id; } XMPP_ROSTER_RESOURCE_REC; typedef struct _XMPP_ROSTER_USER_REC { char *jid; char *name; int subscription; gboolean error; GSList *resources; } XMPP_ROSTER_USER_REC; typedef struct _XMPP_ROSTER_GROUP_REC { char *name; GSList *users; } XMPP_ROSTER_GROUP_REC; __BEGIN_DECLS void rosters_init(void); void rosters_deinit(void); __END_DECLS #endif src/core/rosters.c0000644000175000017500000004157412261362415012261 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "module.h" #include "signals.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "tools.h" #define XMLNS_ROSTER "jabber:iq:roster" const char *xmpp_presence_show[] = { "-", "X", "xa", "dnd", "away", "+", "chat", "online", NULL }; const char *xmpp_subscription[] = { "remove", "none", "to", "from", "both", NULL }; static int func_find_group(gconstpointer group, gconstpointer name) { char *group_name; group_name = ((XMPP_ROSTER_GROUP_REC *)group)->name; if (group_name == name) return 0; if (group_name == NULL || name == NULL) return -1; return strcmp(group_name, name); } static int func_sort_group(gconstpointer group1, gconstpointer group2) { char *group1_name, *group2_name; group1_name = ((XMPP_ROSTER_GROUP_REC *)group1)->name; group2_name = ((XMPP_ROSTER_GROUP_REC *)group2)->name; if (group1_name == NULL) return -1; if (group2_name == NULL) return 1; return strcmp(group1_name, group2_name); } static int func_sort_resource(gconstpointer resource1_ptr, gconstpointer resource2_ptr) { int cmp; XMPP_ROSTER_RESOURCE_REC *resource1, *resource2; resource1 = (XMPP_ROSTER_RESOURCE_REC *)resource1_ptr; resource2 = (XMPP_ROSTER_RESOURCE_REC *)resource2_ptr; if ((cmp = resource2->priority - resource1->priority) == 0 && (cmp = resource2->show - resource1->show) == 0) return strcmp(resource1->name, resource2->name); return cmp; } static int func_sort_user_by_name(XMPP_ROSTER_USER_REC *user1, XMPP_ROSTER_USER_REC *user2) { if (user1->name == NULL && user2->name != NULL) return strcmp(user1->jid, user2->name); if (user1->name != NULL && user2->name == NULL) return strcmp(user1->name, user2->jid); if (user1->name != NULL && user2->name != NULL) return strcmp(user1->name, user2->name); return strcmp(user1->jid, user2->jid); } static int func_sort_user(gconstpointer user1_ptr, gconstpointer user2_ptr) { GSList *resources1_list, *resources2_list; XMPP_ROSTER_USER_REC *user1, *user2; XMPP_ROSTER_RESOURCE_REC *fisrt_resources1, *fisrt_resources2; user1 = (XMPP_ROSTER_USER_REC *)user1_ptr; resources1_list = user1->resources; user2 = (XMPP_ROSTER_USER_REC *)user2_ptr; resources2_list = user2->resources; if (resources1_list == NULL && resources2_list == NULL && user1->error == user2->error) return func_sort_user_by_name(user1, user2); if (user1->error || resources1_list == NULL) return 1; if (user2->error || resources2_list == NULL) return -1; fisrt_resources1 = (XMPP_ROSTER_RESOURCE_REC *)resources1_list->data; fisrt_resources2 = (XMPP_ROSTER_RESOURCE_REC *)resources2_list->data; if (fisrt_resources1->show == fisrt_resources2->show) return func_sort_user_by_name(user1, user2); return fisrt_resources2->show - fisrt_resources1->show; } static XMPP_ROSTER_RESOURCE_REC * create_resource(const char *name) { XMPP_ROSTER_RESOURCE_REC *resource; resource = g_new(XMPP_ROSTER_RESOURCE_REC, 1); resource->name = g_strdup(name == NULL ? "" : name); resource->priority = 0; resource->show= XMPP_PRESENCE_UNAVAILABLE; resource->status = NULL; resource->composing_id = NULL; return resource; } static void cleanup_resource(gpointer data, gpointer user_data) { XMPP_ROSTER_RESOURCE_REC *resource; if (data == NULL) return; resource = (XMPP_ROSTER_RESOURCE_REC *)data; g_free(resource->name); g_free(resource->status); g_free(resource->composing_id); g_free(resource); } static XMPP_ROSTER_USER_REC * create_user(const char *jid, const char *name) { XMPP_ROSTER_USER_REC *user; g_return_val_if_fail(jid != NULL, NULL); user = g_new(XMPP_ROSTER_USER_REC, 1); user->jid = g_strdup(jid); user->name = g_strdup(name); user->subscription = XMPP_SUBSCRIPTION_NONE; user->error = FALSE; user->resources = NULL; return user; } static void cleanup_user(gpointer data, gpointer user_data) { XMPP_ROSTER_USER_REC *user; if (data == NULL) return; user = (XMPP_ROSTER_USER_REC *)data; g_slist_foreach(user->resources, cleanup_resource, NULL); g_slist_free(user->resources); g_free(user->name); g_free(user->jid); g_free(user); } static XMPP_ROSTER_GROUP_REC * create_group(const char *name) { XMPP_ROSTER_GROUP_REC *group; group = g_new(XMPP_ROSTER_GROUP_REC, 1); group->name = g_strdup(name); group->users = NULL; return group; } static void cleanup_group(gpointer data, gpointer user_data) { XMPP_ROSTER_GROUP_REC *group; if (data == NULL) return; group = (XMPP_ROSTER_GROUP_REC *)data; g_slist_foreach(group->users, cleanup_user, group); g_slist_free(group->users); g_free(group->name); g_free(group); } static void roster_cleanup(XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER(server) || server->roster == NULL) return; g_slist_foreach(server->roster, cleanup_group, server); g_slist_free(server->roster); server->roster = NULL; g_slist_foreach(server->my_resources, cleanup_resource, NULL); g_slist_free(server->my_resources); server->my_resources = NULL; } static XMPP_ROSTER_GROUP_REC * find_or_add_group(XMPP_SERVER_REC *server, const char *group_name) { GSList *group_list; XMPP_ROSTER_GROUP_REC *group; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); group_list = g_slist_find_custom(server->roster, group_name, func_find_group); if (group_list == NULL) { group = create_group(group_name); server->roster = g_slist_insert_sorted(server->roster, group, func_sort_group); } else group = group_list->data; return group; } static XMPP_ROSTER_USER_REC * add_user(XMPP_SERVER_REC *server, const char *jid, const char *name, const char *group_name, XMPP_ROSTER_GROUP_REC **return_group) { XMPP_ROSTER_GROUP_REC *group; XMPP_ROSTER_USER_REC *user; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); g_return_val_if_fail(jid != NULL, NULL); group = find_or_add_group(server, group_name); user = create_user(jid, name); group->users = g_slist_append(group->users, user); if (return_group != NULL) *return_group = group; return user; } static XMPP_ROSTER_GROUP_REC * move_user(XMPP_SERVER_REC *server, XMPP_ROSTER_USER_REC *user, XMPP_ROSTER_GROUP_REC *group, const char *group_name) { XMPP_ROSTER_GROUP_REC *new_group; g_return_val_if_fail(IS_XMPP_SERVER(server), group); g_return_val_if_fail(user != NULL, group); new_group = find_or_add_group(server, group_name); group->users = g_slist_remove(group->users, user); new_group->users = g_slist_append(new_group->users, user); return new_group; } static void update_subscription(XMPP_SERVER_REC *server, XMPP_ROSTER_USER_REC *user, XMPP_ROSTER_GROUP_REC *group, const char *subscription) { g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(user != NULL); g_return_if_fail(group != NULL); g_return_if_fail(subscription != NULL); if (g_ascii_strcasecmp(subscription, xmpp_subscription[XMPP_SUBSCRIPTION_NONE]) == 0) user->subscription = XMPP_SUBSCRIPTION_NONE; else if (g_ascii_strcasecmp(subscription, xmpp_subscription[XMPP_SUBSCRIPTION_FROM]) == 0) user->subscription = XMPP_SUBSCRIPTION_FROM; else if (g_ascii_strcasecmp(subscription, xmpp_subscription[XMPP_SUBSCRIPTION_TO]) == 0) user->subscription = XMPP_SUBSCRIPTION_TO; else if (g_ascii_strcasecmp(subscription, xmpp_subscription[XMPP_SUBSCRIPTION_BOTH]) == 0) user->subscription = XMPP_SUBSCRIPTION_BOTH; else if (g_ascii_strcasecmp(subscription, xmpp_subscription[XMPP_SUBSCRIPTION_REMOVE]) == 0) { group->users = g_slist_remove(group->users, user); cleanup_user(user, server); /* remove empty group */ if (group->users == NULL) { server->roster = g_slist_remove(server->roster, group); cleanup_group(group, server); } } } static void update_user(XMPP_SERVER_REC *server, const char *jid, const char *subscription, const char *name, const char *group_name) { XMPP_ROSTER_GROUP_REC *group; XMPP_ROSTER_USER_REC *user; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(jid != NULL); user = rosters_find_user(server->roster, jid, &group, NULL); if (user == NULL) user = add_user(server, jid, name, group_name, &group); else { /* move to another group and sort it */ if ((group->name == NULL && group_name != NULL) || (group->name != NULL && group_name == NULL) || (group->name != NULL && group_name != NULL && strcmp(group->name, group_name) != 0)) { group = move_user(server, user, group, group_name); group->users = g_slist_sort(group->users, func_sort_user); } /* change name */ if ((user->name == NULL && name != NULL) || (user->name != NULL && name == NULL) || (user->name != NULL && name != NULL && strcmp(user->name, name) != 0)) { g_free(user->name); user->name = g_strdup(name); group->users = g_slist_sort(group->users, func_sort_user); } } update_subscription(server, user, group, subscription); } static void update_user_presence(XMPP_SERVER_REC *server, const char *full_jid, const char *show_str, const char *status, const char *priority_str) { XMPP_ROSTER_GROUP_REC *group; XMPP_ROSTER_USER_REC *user; XMPP_ROSTER_RESOURCE_REC *resource; char *jid, *res; int show, priority; gboolean new, own; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(full_jid != NULL); new = own = FALSE; jid = xmpp_strip_resource(full_jid); res = xmpp_extract_resource(full_jid); user = rosters_find_user(server->roster, jid, &group, NULL); if (user == NULL) { if (!(own = strcmp(jid, server->jid) == 0 && strcmp(res, server->resource) != 0)) goto out; } else user->error = FALSE; /* find resource or create it if it doesn't exist */ resource = rosters_find_resource(!own ? user->resources : server->my_resources, res); if (resource == NULL) { resource = create_resource(res); new = TRUE; if (!own) user->resources = g_slist_prepend(user->resources, resource); else server->my_resources = g_slist_prepend(server->my_resources, resource); signal_emit("xmpp presence online", 4, server, full_jid, jid, res); } show = xmpp_get_show(show_str); priority = (priority_str != NULL) ? atoi(priority_str) : resource->priority; if (new || xmpp_presence_changed(show, resource->show, status, resource->status, priority, resource->priority)) { resource->show = show; resource->status = g_strdup(status); resource->priority = priority; if (!own) { user->resources = g_slist_sort( user->resources, func_sort_resource); group->users = g_slist_sort(group->users, func_sort_user); } else server->my_resources = g_slist_sort( server->my_resources, func_sort_resource); signal_emit("xmpp presence changed", 4, server, full_jid, resource->show, resource->status); } out: g_free(jid); g_free(res); } static void user_unavailable(XMPP_SERVER_REC *server, const char *full_jid, const char *status) { XMPP_ROSTER_GROUP_REC *group; XMPP_ROSTER_USER_REC *user; XMPP_ROSTER_RESOURCE_REC *resource; char *jid, *res; gboolean own; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(full_jid != NULL); own = FALSE; jid = xmpp_strip_resource(full_jid); res = xmpp_extract_resource(full_jid); user = rosters_find_user(server->roster, jid, &group, NULL); if (user == NULL) { if (!(own = strcmp(jid, server->jid) == 0)) goto out; } else user->error = FALSE; resource = rosters_find_resource(!own ? user->resources : server->my_resources, res); if (resource == NULL) goto out; signal_emit("xmpp presence offline", 4, server, full_jid, jid, res); signal_emit("xmpp presence changed", 4, server, full_jid, XMPP_PRESENCE_UNAVAILABLE, status); if (!own) user->resources = g_slist_remove(user->resources, resource); else server->my_resources = g_slist_remove(server->my_resources, resource); cleanup_resource(resource, NULL); if (!own) /* sort the group */ group->users = g_slist_sort(group->users, func_sort_user); out: g_free(jid); g_free(res); } static void user_presence_error(XMPP_SERVER_REC *server, const char *full_jid) { XMPP_ROSTER_GROUP_REC *group; XMPP_ROSTER_USER_REC *user; XMPP_ROSTER_RESOURCE_REC *resource; char *jid, *res; gboolean own; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(full_jid != NULL); own = FALSE; jid = xmpp_strip_resource(full_jid); res = xmpp_extract_resource(full_jid); user = rosters_find_user(server->roster, jid, &group, NULL); if (user == NULL && !(own = strcmp(jid, server->jid) == 0)) goto out; resource = rosters_find_resource(!own ? user->resources : server->my_resources, res); if (resource != NULL) { resource->show = XMPP_PRESENCE_ERROR; if (!own) /* sort the group */ group->users = g_slist_sort(group->users, func_sort_user); signal_emit("xmpp presence changed", 4, server, full_jid, XMPP_PRESENCE_ERROR, NULL); } else if (user != NULL) user->error = TRUE; out: g_free(jid); g_free(res); } static void sig_recv_presence(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node, *node_show, *node_priority; char *status; if (server->ischannel(SERVER(server), from)) return; switch(type) { case LM_MESSAGE_SUB_TYPE_AVAILABLE: node_show = lm_message_node_get_child(lmsg->node, "show"); node = lm_message_node_get_child(lmsg->node, "status"); status = node != NULL ? xmpp_recode_in(node->value) : NULL; node_priority = lm_message_node_get_child(lmsg->node, "priority"); update_user_presence(server, from, node_show != NULL ? node_show->value : NULL, status, node_priority != NULL ? node_priority->value : NULL); g_free(status); break; case LM_MESSAGE_SUB_TYPE_UNAVAILABLE: node = lm_message_node_get_child(lmsg->node, "status"); status = node != NULL ? xmpp_recode_in(node->value) : NULL; user_unavailable(server, from, status); g_free(status); break; case LM_MESSAGE_SUB_TYPE_SUBSCRIBE: node = lm_message_node_get_child(lmsg->node, "status"); status = node != NULL ? xmpp_recode_in(node->value) : NULL; signal_emit("xmpp presence subscribe", 3, server, from, status); g_free(status); break; case LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE: signal_emit("xmpp presence unsubscribe", 2, server, from); break; case LM_MESSAGE_SUB_TYPE_SUBSCRIBED: signal_emit("xmpp presence subscribed", 2, server, from); break; case LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED: signal_emit("xmpp presence unsubscribed", 2, server, from); break; case LM_MESSAGE_SUB_TYPE_ERROR: user_presence_error(server, from); break; } } static void sig_recv_iq(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node, *item, *group_node; char *jid, *name, *group; const char *subscription; if (type != LM_MESSAGE_SUB_TYPE_RESULT && type != LM_MESSAGE_SUB_TYPE_SET) return; node = lm_find_node(lmsg->node, "query", "xmlns", XMLNS_ROSTER); if (node == NULL) return; for (item = node->children; item != NULL; item = item->next) { if (strcmp(item->name, "item") != 0) continue; jid = xmpp_recode_in(lm_message_node_get_attribute(item, "jid")); name = xmpp_recode_in(lm_message_node_get_attribute(item, "name")); group_node = lm_message_node_get_child(item, "group"); group = group_node != NULL ? xmpp_recode_in(group_node->value) : NULL; subscription = lm_message_node_get_attribute(item, "subscription"); update_user(server, jid, subscription, name, group); g_free(jid); g_free(name); g_free(group); } } static void sig_connected(XMPP_SERVER_REC *server) { LmMessage *lmsg; LmMessageNode *node; if (!IS_XMPP_SERVER(server)) return; signal_emit("xmpp server status", 2, server, "Requesting the roster."); lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, "xmlns", "jabber:iq:roster"); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } void rosters_init(void) { signal_add("server connected", sig_connected); signal_add_first("server disconnected", roster_cleanup); signal_add("xmpp recv presence", sig_recv_presence); signal_add("xmpp recv iq", sig_recv_iq); } void rosters_deinit(void) { signal_remove("server connected", sig_connected); signal_remove("server disconnected", roster_cleanup); signal_remove("xmpp recv presence", sig_recv_presence); signal_remove("xmpp recv iq", sig_recv_iq); } src/core/xmpp-servers.c0000644000175000017500000004077012261362415013230 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include "module.h" #include "network.h" #include "recode.h" #include "settings.h" #include "signals.h" #include "xmpp-servers.h" #include "protocol.h" #include "rosters-tools.h" #include "tools.h" static void channels_join(SERVER_REC *server, const char *data, int automatic) { } static int isnickflag_func(SERVER_REC *server, char flag) { return FALSE; } static int ischannel_func(SERVER_REC *server, const char *data) { return FALSE; } static const char * get_nick_flags(SERVER_REC *server) { return ""; } static void send_message(SERVER_REC *server, const char *target, const char *msg, int target_type) { LmMessage *lmsg; char *str, *recoded; if (!IS_XMPP_SERVER(server)) return; g_return_if_fail(target != NULL); g_return_if_fail(msg != NULL); if (target_type == SEND_TARGET_CHANNEL) { recoded = xmpp_recode_out(target); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_GROUPCHAT); } else { str = rosters_resolve_name(XMPP_SERVER(server), target); recoded = xmpp_recode_out(str != NULL ? str : target); g_free(str); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_CHAT); } g_free(recoded); /* ugly from irssi: recode the sent message back */ str = recode_in(server, msg, target); recoded = xmpp_recode_out(str); g_free(str); lm_message_node_add_child(lmsg->node, "body", recoded); g_free(recoded); signal_emit("xmpp send message", 2, server, lmsg); lm_message_unref(lmsg); } static void server_cleanup(XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER(server)) return; if (server->timeout_tag) g_source_remove(server->timeout_tag); if (lm_connection_get_state(server->lmconn) != LM_CONNECTION_STATE_CLOSED) lm_connection_close(server->lmconn, NULL); lm_connection_unref(server->lmconn); g_free(server->jid); g_free(server->user); g_free(server->domain); g_free(server->resource); g_free(server->ping_id); } SERVER_REC * xmpp_server_init_connect(SERVER_CONNECT_REC *connrec) { XMPP_SERVER_REC *server; XMPP_SERVER_CONNECT_REC *conn = (XMPP_SERVER_CONNECT_REC *)connrec; char *recoded; if (conn->address == NULL || conn->address[0] == '\0') return NULL; if (conn->nick == NULL || conn->nick[0] == '\0') return NULL; g_return_val_if_fail(IS_XMPP_SERVER_CONNECT(conn), NULL); server = g_new0(XMPP_SERVER_REC, 1); server->chat_type = XMPP_PROTOCOL; server->user = xmpp_extract_user(conn->nick); server->domain = xmpp_have_domain(conn->nick) ? xmpp_extract_domain(conn->nick) : g_strdup(conn->address); server->jid = xmpp_have_domain(conn->nick) ? xmpp_strip_resource(conn->nick) : g_strconcat(server->user, "@", server->domain, (void *)NULL); server->resource = xmpp_extract_resource(conn->nick); if (server->resource == NULL) server->resource = g_strdup("irssi-xmpp"); server->priority = settings_get_int("xmpp_priority"); if (xmpp_priority_out_of_bound(server->priority)) server->priority = 0; server->ping_id = NULL; server->server_features = NULL; server->my_resources = NULL; server->roster = NULL; server->msg_handlers = NULL; server->channels_join = channels_join; server->isnickflag = isnickflag_func; server->ischannel = ischannel_func; server->get_nick_flags = get_nick_flags; server->send_message = send_message; server->connrec = (XMPP_SERVER_CONNECT_REC *)conn; server_connect_ref(connrec); /* don't use irssi's sockets */ server->connrec->no_connect = TRUE; server->connect_pid = -1; if (server->connrec->port <= 0) server->connrec->port = (server->connrec->use_ssl) ? LM_CONNECTION_DEFAULT_PORT_SSL : LM_CONNECTION_DEFAULT_PORT; if (conn->real_jid == NULL) conn->real_jid = conn->nick; else g_free(conn->nick); conn->nick = g_strdup(settings_get_bool("xmpp_set_nick_as_username") ? server->user : server->jid); /* init loudmouth connection structure */ server->lmconn = lm_connection_new(NULL); lm_connection_set_server(server->lmconn, server->connrec->address); lm_connection_set_port(server->lmconn, server->connrec->port); recoded = xmpp_recode_out(server->jid); lm_connection_set_jid(server->lmconn, recoded); g_free(recoded); lm_connection_set_keep_alive_rate(server->lmconn, 30); server->timeout_tag = 0; server_connect_init((SERVER_REC *)server); server->connect_tag = 1; return (SERVER_REC *)server; } static LmSSLResponse lm_ssl_cb(LmSSL *ssl, LmSSLStatus status, gpointer user_data) { XMPP_SERVER_REC *server; if ((server = XMPP_SERVER(user_data)) == NULL) return LM_SSL_RESPONSE_CONTINUE; switch (status) { case LM_SSL_STATUS_NO_CERT_FOUND: g_warning("SSL (%s): no certificate found", server->connrec->address); break; case LM_SSL_STATUS_UNTRUSTED_CERT: g_warning("SSL (%s): certificate is not trusted", server->connrec->address); break; case LM_SSL_STATUS_CERT_EXPIRED: g_warning("SSL (%s): certificate has expired", server->connrec->address); break; case LM_SSL_STATUS_CERT_NOT_ACTIVATED: g_warning("SSL (%s): certificate has not been activated", server->connrec->address); break; case LM_SSL_STATUS_CERT_HOSTNAME_MISMATCH: g_warning("SSL (%s): certificate hostname does not match " "expected hostname", server->connrec->address); break; case LM_SSL_STATUS_CERT_FINGERPRINT_MISMATCH: g_warning("SSL (%s): certificate fingerprint does not match " "expected fingerprint", server->connrec->address); break; case LM_SSL_STATUS_GENERIC_ERROR: g_warning("SSL (%s): generic error", server->connrec->address); break; } return LM_SSL_RESPONSE_CONTINUE; } static void lm_close_cb(LmConnection *connection, LmDisconnectReason reason, gpointer user_data) { XMPP_SERVER_REC *server; if ((server = XMPP_SERVER(user_data)) == NULL || !server->connected || reason == LM_DISCONNECT_REASON_OK) return; server->connection_lost = TRUE; server_disconnect(SERVER(server)); } static void lm_auth_cb(LmConnection *connection, gboolean success, gpointer user_data) { XMPP_SERVER_REC *server; if ((server = XMPP_SERVER(user_data)) == NULL) return; if (!success) { server_connect_failed(SERVER(server), "Authentication failed"); return; } signal_emit("xmpp server status", 2, server, "Authenticated successfully."); /* finnish connection process */ lookup_servers = g_slist_remove(lookup_servers, server); g_source_remove(server->connect_tag); server->connect_tag = -1; server->show = XMPP_PRESENCE_AVAILABLE; server->connected = TRUE; if (server->timeout_tag) { g_source_remove(server->timeout_tag); server->timeout_tag = 0; } server_connect_finished(SERVER(server)); server->real_connect_time = server->connect_time; } /* * Displays input prompt on command line and takes input data from user * From irssi-silc (silc-client/lib/silcutil/silcutil.c) */ static char * get_password() { char input[2048], *ret = NULL; int fd; #ifndef DISABLE_TERMIOS struct termios to; struct termios to_old; if ((fd = open("/dev/tty", O_RDONLY)) < 0) { g_warning("Cannot open /dev/tty: %s\n", strerror(errno)); return NULL; } signal(SIGINT, SIG_IGN); /* Get terminal info */ tcgetattr(fd, &to); to_old = to; /* Echo OFF, and assure we can prompt and get input */ to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); to.c_lflag |= ICANON; to.c_cc[VMIN] = 255; tcsetattr(fd, TCSANOW, &to); printf("\tXMPP Password: "); fflush(stdout); memset(input, 0, sizeof(input)); if ((read(fd, input, sizeof(input))) < 0) { g_warning("Cannot read from /dev/tty: %s\n", strerror(errno)); tcsetattr(fd, TCSANOW, &to_old); return NULL; } if (strlen(input) <= 1) { tcsetattr(fd, TCSANOW, &to_old); return NULL; } if ((ret = strchr(input, '\n')) != NULL) *ret = '\0'; /* Restore old terminfo */ tcsetattr(fd, TCSANOW, &to_old); signal(SIGINT, SIG_DFL); ret = g_strdup(input); memset(input, 0, sizeof(input)); #endif /* DISABLE_TERMIOS */ return ret; } static void lm_open_cb(LmConnection *connection, gboolean success, gpointer user_data) { XMPP_SERVER_REC *server; IPADDR ip; char *host; char *recoded_user, *recoded_password, *recoded_resource; if ((server = XMPP_SERVER(user_data)) == NULL || !success) return; /* get the server address */ host = lm_connection_get_local_host(server->lmconn); if (host != NULL) { net_host2ip(host, &ip); signal_emit("server connecting", 2, server, &ip); g_free(host); } else signal_emit("server connecting", 1, server); if (server->connrec->use_ssl) signal_emit("xmpp server status", 2, server, "Using SSL encryption."); else if (lm_ssl_get_use_starttls(lm_connection_get_ssl(server->lmconn))) signal_emit("xmpp server status", 2, server, "Using STARTTLS encryption."); recoded_user = xmpp_recode_out(server->user); /* prompt for password or re-use typed password */ if (server->connrec->prompted_password != NULL) { g_free_not_null(server->connrec->password); server->connrec->password = g_strdup(server->connrec->prompted_password); } else if (server->connrec->password == NULL || *(server->connrec->password) == '\0' || *(server->connrec->password) == '\r') { g_free_not_null(server->connrec->password); server->connrec->prompted_password = get_password(); signal_emit("send command", 1, "redraw"); if (server->connrec->prompted_password != NULL) server->connrec->password = g_strdup(server->connrec->prompted_password); else server->connrec->password = g_strdup(""); } recoded_password = xmpp_recode_out(server->connrec->password); recoded_resource = xmpp_recode_out(server->resource); lm_connection_authenticate(connection, recoded_user, recoded_password, recoded_resource, lm_auth_cb, server, NULL, NULL); g_free(recoded_user); g_free(recoded_password); g_free(recoded_resource); } gboolean set_ssl(LmConnection *lmconn, GError **error, gpointer user_data, gboolean use_starttls) { LmSSL *ssl; if (!lm_ssl_is_supported() && error != NULL) { *error = g_new(GError, 1); (*error)->message = g_strdup("SSL is not supported in this build"); return FALSE; } ssl = lm_ssl_new(NULL, lm_ssl_cb, user_data, NULL); lm_connection_set_ssl(lmconn, ssl); if (use_starttls) lm_ssl_use_starttls(ssl, TRUE, FALSE); lm_ssl_unref(ssl); return TRUE; } gboolean set_proxy(LmConnection *lmconn, GError **error) { LmProxy *proxy; LmProxyType type; const char *str; char *recoded; str = settings_get_str("xmpp_proxy_type"); if (str != NULL && g_ascii_strcasecmp(str, XMPP_PROXY_HTTP) == 0) type = LM_PROXY_TYPE_HTTP; else { if (error != NULL) { *error = g_new(GError, 1); (*error)->message = g_strdup("Invalid proxy type"); } return FALSE; } str = settings_get_str("xmpp_proxy_address"); if (str == NULL || *str == '\0') { if (error != NULL) { *error = g_new(GError, 1); (*error)->message = g_strdup("Proxy address not specified"); } return FALSE; } int port = settings_get_int("xmpp_proxy_port"); if (port <= 0) { if (error != NULL) { *error = g_new(GError, 1); (*error)->message = g_strdup("Invalid proxy port range"); } return FALSE; } proxy = lm_proxy_new_with_server(type, str, port); str = settings_get_str("xmpp_proxy_user"); if (str != NULL && *str != '\0') { recoded = xmpp_recode_out(str); lm_proxy_set_username(proxy, recoded); g_free(recoded); } str = settings_get_str("xmpp_proxy_password"); if (str != NULL && *str != '\0') { recoded = xmpp_recode_out(str); lm_proxy_set_password(proxy, recoded); g_free(recoded); } lm_connection_set_proxy(lmconn, proxy); lm_proxy_unref(proxy); return TRUE; } static int check_connection_timeout(XMPP_SERVER_REC *server) { if (g_slist_find(lookup_servers, server) == NULL) return FALSE; if (!server->connected) { g_warning("%s: no response from server", server->connrec->address); server->connection_lost = TRUE; server_disconnect(SERVER(server)); } else server->timeout_tag = 0; return FALSE; } void xmpp_server_connect(XMPP_SERVER_REC *server) { GError *error; const char *err_msg; if (!IS_XMPP_SERVER(server)) return; error = NULL; err_msg = NULL; if (server->connrec->use_ssl) { if (!set_ssl(server->lmconn, &error, server, FALSE)) { err_msg = "Cannot init ssl"; goto err; } } else set_ssl(server->lmconn, &error, server, TRUE); if (settings_get_bool("xmpp_use_proxy") && !set_proxy(server->lmconn, &error)) { err_msg = "Cannot set proxy"; goto err; } lm_connection_set_disconnect_function(server->lmconn, lm_close_cb, server, NULL); lookup_servers = g_slist_append(lookup_servers, server); signal_emit("server looking", 1, server); server->timeout_tag = g_timeout_add( settings_get_time("server_connect_timeout"), (GSourceFunc)check_connection_timeout, server); if (!lm_connection_open(server->lmconn, lm_open_cb, server, NULL, &error)) { err_msg = "Connection failed"; goto err; } return; err: server->connection_lost = TRUE; if (error != NULL) { server_connect_failed(SERVER(server), error->message); g_error_free(error); } else server_connect_failed(SERVER(server), err_msg); } static void sig_connected(XMPP_SERVER_REC *server) { LmMessage *lmsg; char *str; if (!IS_XMPP_SERVER(server) || (server->connrec->reconnection && xmpp_presence_changed(server->connrec->show, server->show, server->connrec->away_reason, server->away_reason, server->connrec->priority, server->priority))) return; /* set presence available */ lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_AVAILABLE); str = g_strdup_printf("%d", server->priority); lm_message_node_add_child(lmsg->node, "priority", str); g_free(str); signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); } static void sig_server_quit(XMPP_SERVER_REC *server, char *reason) { LmMessage *lmsg; char *str; if (!IS_XMPP_SERVER(server)) return; lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_UNAVAILABLE); str = xmpp_recode_out((reason != NULL) ? reason : settings_get_str("quit_message")); lm_message_node_add_child(lmsg->node, "status", str); g_free(str); signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); } static void disconnect_all(void) { GSList *tmp, *next; for (tmp = lookup_servers; tmp != NULL; tmp = next) { next = tmp->next; if (IS_XMPP_SERVER(tmp->data)) server_connect_failed(SERVER(tmp->data), NULL); } for (tmp = servers; tmp != NULL; tmp = next) { next = tmp->next; if (IS_XMPP_SERVER(tmp->data)) server_disconnect(SERVER(tmp->data)); } } static void sig_session_save(void) { /* We don't support /UPGRADE, so disconnect all servers * before performing it. */ disconnect_all(); } void xmpp_servers_init(void) { signal_add_last("server connected", sig_connected); signal_add_last("server disconnected", server_cleanup); signal_add_last("server connect failed", server_cleanup); signal_add("server quit", sig_server_quit); signal_add_first("session save", sig_session_save); settings_add_int("xmpp", "xmpp_priority", 0); settings_add_int("xmpp", "xmpp_priority_away", -1); settings_add_bool("xmpp_lookandfeel", "xmpp_set_nick_as_username", FALSE); settings_add_bool("xmpp_proxy", "xmpp_use_proxy", FALSE); settings_add_str("xmpp_proxy", "xmpp_proxy_type", "http"); settings_add_str("xmpp_proxy", "xmpp_proxy_address", NULL); settings_add_int("xmpp_proxy", "xmpp_proxy_port", 8080); settings_add_str("xmpp_proxy", "xmpp_proxy_user", NULL); settings_add_str("xmpp_proxy", "xmpp_proxy_password", NULL); } void xmpp_servers_deinit(void) { /* disconnect all servers before unloading the module */ disconnect_all(); signal_remove("server connected", sig_connected); signal_remove("server disconnected", server_cleanup); signal_remove("server connect failed", server_cleanup); signal_remove("server quit", sig_server_quit); signal_remove("session save", sig_session_save); } src/core/tools.c0000644000175000017500000001036512261362415011712 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "recode.h" #include "settings.h" #include "signals.h" #define XMPP_PRIORITY_MIN -128 #define XMPP_PRIORITY_MAX 127 static const char *utf8_charset = "UTF-8"; static gboolean xmpp_get_local_charset(G_CONST_RETURN char **charset) { *charset = settings_get_str("term_charset"); if (is_valid_charset(*charset)) return (g_ascii_strcasecmp(*charset, utf8_charset) == 0); return g_get_charset(charset); } char * xmpp_recode_out(const char *str) { G_CONST_RETURN char *charset; char *recoded, *stripped; if (str == NULL || *str == '\0') return NULL; recoded = stripped = NULL; signal_emit("xmpp formats strip codes", 2, str, &stripped); if (stripped != NULL) str = stripped; if (!xmpp_get_local_charset(&charset) && charset != NULL) recoded = g_convert_with_fallback(str, -1, utf8_charset, charset, NULL, NULL, NULL, NULL); recoded = recoded != NULL ? recoded : g_strdup(str); g_free(stripped); return recoded; } char * xmpp_recode_in(const char *str) { G_CONST_RETURN char *charset; char *recoded, *to = NULL; if (str == NULL || *str == '\0') return NULL; if (xmpp_get_local_charset(&charset) || charset == NULL) return g_strdup(str); if (settings_get_bool("recode_transliterate") && g_ascii_strcasecmp(charset, "//TRANSLIT") != 0) charset = to = g_strconcat(charset ,"//TRANSLIT", (void *)NULL); recoded = g_convert_with_fallback(str, -1, charset, utf8_charset, NULL, NULL, NULL, NULL); g_free(to); return (recoded != NULL) ? recoded : g_strdup(str); } char * xmpp_find_resource_sep(const char *jid) { return jid == NULL ? NULL : g_utf8_strchr(jid, -1, '/'); } char * xmpp_extract_resource(const char *jid) { char *pos; g_return_val_if_fail(jid != NULL, NULL); pos = xmpp_find_resource_sep(jid); return (pos != NULL) ? g_strdup(pos + 1) : NULL; } char * xmpp_strip_resource(const char *jid) { char *pos; g_return_val_if_fail(jid != NULL, NULL); pos = xmpp_find_resource_sep(jid); return (pos != NULL) ? g_strndup(jid, pos - jid) : g_strdup(jid); } char * xmpp_extract_user(const char *jid) { char *pos; g_return_val_if_fail(jid != NULL, NULL); pos = g_utf8_strchr(jid, -1, '@'); return (pos != NULL) ? g_strndup(jid, pos - jid) : xmpp_strip_resource(jid); } char * xmpp_extract_domain(const char *jid) { char *pos1, *pos2; pos1 = g_utf8_strchr(jid, -1, '@'); pos2 = xmpp_find_resource_sep(jid); if (pos1 == NULL) return NULL; if (pos2 != NULL && pos2 < pos1) return g_strdup(pos1 + 1); return (pos2 != NULL) ? g_strndup(pos1 + 1, pos2 - pos1 - 1) : g_strdup(pos1 + 1); } gboolean xmpp_have_domain(const char *jid) { char *pos; g_return_val_if_fail(jid != NULL, FALSE); pos = g_utf8_strchr(jid, -1, '@'); return (pos != NULL && *(pos+1) != '\0'); } gboolean xmpp_have_resource(const char *jid) { char *pos; g_return_val_if_fail(jid != NULL, FALSE); pos = xmpp_find_resource_sep(jid); return (pos != NULL && *(pos+1) != '\0'); } gboolean xmpp_priority_out_of_bound(const int priority) { return (XMPP_PRIORITY_MIN <= priority && priority <= XMPP_PRIORITY_MAX) ? FALSE : TRUE; } gboolean xmpp_presence_changed(const int show, const int old_show, const char *status, const char *old_status, const int priority, const int old_priority) { return (show != old_show) || (status == NULL && old_status != NULL) || (status != NULL && old_status == NULL) || (status != NULL && old_status != NULL && strcmp(status, old_status) != 0) || (priority != old_priority); } src/core/xmpp-settings.c0000644000175000017500000000526412261362415013376 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "settings.h" #include "signals.h" #include "xmpp-servers.h" #include "rosters.h" void read_settings(void) { GSList *tmp; XMPP_SERVER_REC *server; for (tmp = servers; tmp != NULL; tmp = tmp->next) { if ((server = XMPP_SERVER(tmp->data)) == NULL) continue; /* update priority */ if (server->show == XMPP_PRESENCE_AWAY) { if (server->priority != settings_get_int("xmpp_priority_away")) signal_emit("xmpp set presence", 4, server, server->show, server->away_reason, settings_get_int("xmpp_priority_away")); } else { if (server->priority != settings_get_int("xmpp_priority")) signal_emit("xmpp set presence", 4, server, server->show, server->away_reason, settings_get_int("xmpp_priority")); } /* update nick */ if (settings_get_bool("xmpp_set_nick_as_username")) { if (strcmp(server->nick, server->user) != 0) { g_free(server->nick); server->nick = g_strdup(server->user); } } else { if (strcmp(server->nick, server->jid) != 0) { g_free(server->nick); server->nick = g_strdup(server->jid); } } } #if 0 const char *str; /* check validity */ str = settings_get_str("xmpp_proxy_type"); /* TODO print error message */ if (settings_get_bool("xmpp_use_proxy") && (str == NULL || g_ascii_strcasecmp(str, XMPP_PROXY_HTTP) != 0)) ; str = settings_get_str("xmpp_default_away_mode"); if (str == NULL || g_ascii_strcasecmp(str, xmpp_presence_show[XMPP_PRESENCE_AWAY]) != 0 || g_ascii_strcasecmp(str, xmpp_presence_show[XMPP_PRESENCE_CHAT]) != 0 || g_ascii_strcasecmp(str, xmpp_presence_show[XMPP_PRESENCE_DND]) != 0 || g_ascii_strcasecmp(str, xmpp_presence_show[XMPP_PRESENCE_XA]) != 0 || g_ascii_strcasecmp(str, xmpp_presence_show[XMPP_PRESENCE_ONLINE]) != 0) ; #endif } void xmpp_settings_init(void) { signal_add("setup changed", (SIGNAL_FUNC)read_settings); } void xmpp_settings_deinit(void) { signal_remove("setup changed", (SIGNAL_FUNC)read_settings); } src/core/xmpp-servers.h0000644000175000017500000000260512261362415013230 0ustar fsfs#ifndef __XMPP_SERVERS_H #define __XMPP_SERVERS_H #include "chat-protocols.h" #include "servers.h" #include "loudmouth/loudmouth.h" #include "loudmouth-tools.h" #define XMPP_PROXY_HTTP "http" /* returns XMPP_SERVER_REC if it's XMPP server, NULL if it isn't */ #define XMPP_SERVER(server) \ PROTO_CHECK_CAST(SERVER(server), XMPP_SERVER_REC, chat_type, "XMPP") #define XMPP_SERVER_CONNECT(conn) \ PROTO_CHECK_CAST(SERVER_CONNECT(conn), XMPP_SERVER_CONNECT_REC, \ chat_type, "XMPP") #define IS_XMPP_SERVER(server) \ (XMPP_SERVER(server) ? TRUE : FALSE) #define IS_XMPP_SERVER_CONNECT(conn) \ (XMPP_SERVER_CONNECT(conn) ? TRUE : FALSE) struct _XMPP_SERVER_CONNECT_REC { #include "server-connect-rec.h" GSList *channels_list; int show; int priority; char *real_jid; char *prompted_password; }; #define STRUCT_SERVER_CONNECT_REC XMPP_SERVER_CONNECT_REC struct _XMPP_SERVER_REC { #include "server-rec.h" char *jid; char *user; char *domain; char *resource; int show; int priority; char *ping_id; GSList *server_features; GSList *my_resources; GSList *roster; int timeout_tag; LmConnection *lmconn; GSList *msg_handlers; }; __BEGIN_DECLS SERVER_REC *xmpp_server_init_connect(SERVER_CONNECT_REC *); void xmpp_server_connect(XMPP_SERVER_REC *); void xmpp_servers_init(void); void xmpp_servers_deinit(void); __END_DECLS #endif src/core/protocol.h0000644000175000017500000000023612261362415012414 0ustar fsfs#ifndef __PROTOCOL_H #define __PROTOCOL_H #include "xmpp-servers.h" __BEGIN_DECLS void protocol_init(void); void protocol_deinit(void); __END_DECLS #endif src/core/xmpp-queries.c0000644000175000017500000000423012261362415013203 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "channels.h" #include "nicklist.h" #include "signals.h" #include "xmpp-queries.h" #include "rosters-tools.h" #include "tools.h" QUERY_REC * xmpp_query_create(const char *server_tag, const char *data, int automatic) { XMPP_QUERY_REC *rec, *rec_tmp; XMPP_SERVER_REC *server; CHANNEL_REC *channel; NICK_REC *nick; const char *channel_name; g_return_val_if_fail(server_tag != NULL, NULL); g_return_val_if_fail(data != NULL, NULL); if ((server = XMPP_SERVER(server_find_tag(server_tag))) == NULL) return NULL; rec = g_new0(XMPP_QUERY_REC, 1); rec->chat_type = XMPP_PROTOCOL; /* query created from a channel */ channel_name = NULL; signal_emit("xmpp windows get active channel", 1, &channel_name); if (channel_name != NULL) { channel = channel_find(SERVER(server), channel_name); if (channel != NULL) { nick = nicklist_find(channel, data); if (nick != NULL) rec->name = g_strdup(nick->host); } } if (rec->name == NULL) rec->name = rosters_resolve_name(server, data); if (rec->name != NULL) { /* test if the query already exist */ if ((rec_tmp = xmpp_query_find(server, rec->name)) != NULL) { g_free(rec->name); g_free(rec); signal_emit("xmpp query raise", 2, server, rec_tmp); return NULL; } } else rec->name = g_strdup(data); rec->server_tag = g_strdup(server_tag); query_init((QUERY_REC *)rec, automatic); rec->composing_time = 0; rec->composing_visible = FALSE; return (QUERY_REC *)rec; } src/core/xmpp-queries.h0000644000175000017500000000124612261362415013214 0ustar fsfs#ifndef __XMPP_QUERIES_H #define __XMPP_QUERIES_H #include "queries.h" #include "xmpp-servers.h" /* Returns XMPP_QUERY_REC if it's XMPP query, NULL if it isn't. */ #define XMPP_QUERY(query) \ PROTO_CHECK_CAST(QUERY(query), XMPP_QUERY_REC, chat_type, "XMPP") #define IS_XMPP_QUERY(query) \ (XMPP_QUERY(query) ? TRUE : FALSE) #define xmpp_query_find(server, name) \ XMPP_QUERY(query_find(SERVER(server), name)) #define STRUCT_SERVER_REC XMPP_SERVER_REC struct _XMPP_QUERY_REC { #include "query-rec.h" time_t composing_time; gboolean composing_visible; }; __BEGIN_DECLS QUERY_REC *xmpp_query_create(const char *, const char *, int); __END_DECLS #endif src/core/stanzas.h0000644000175000017500000000017712261362415012242 0ustar fsfs#ifndef __STANZAS_H #define __STANZAS_H __BEGIN_DECLS void stanzas_init(void); void stanzas_deinit(void); __END_DECLS #endif src/core/xmpp-servers-reconnect.h0000644000175000017500000000027312261362415015205 0ustar fsfs#ifndef __XMPP_SERVERS_RECONNECT_H #define __XMPP_SERVERS_RECONNECT_H __BEGIN_DECLS void xmpp_servers_reconnect_init(void); void xmpp_servers_reconnect_deinit(void); __END_DECLS #endif src/core/loudmouth-tools.c0000644000175000017500000000241212261362415013722 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "loudmouth/loudmouth.h" LmMessageNode * lm_find_node(LmMessageNode *node, const char *name, const char *attribute, const char *value) { LmMessageNode *l; const char *v; g_return_val_if_fail(name != NULL, NULL); g_return_val_if_fail(attribute != NULL, NULL); g_return_val_if_fail(value != NULL, NULL); if (node == NULL) return NULL; for (l = node->children; l != NULL; l = l->next) if (strcmp(l->name, name) == 0) { v = lm_message_node_get_attribute(l, attribute); if (v != NULL && strcmp(value, v) == 0) return l; } return NULL; } src/core/xmpp-commands.c0000644000175000017500000004304312261362415013334 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "channels.h" #include "nicklist.h" #include "recode.h" #include "settings.h" #include "signals.h" #include "window-item-def.h" #include "xmpp-commands.h" #include "xmpp-queries.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "tools.h" const char *xmpp_commands[] = { "away", "quote", "roster", "whois", "presence", NULL }; const char *xmpp_command_roster[] = { "full", "add", "remove", "name", "group", NULL }; const char *xmpp_command_presene[] = { "accept", "deny", "subscribe", "unsubscribe", NULL }; static char * cmd_connect_get_line(const char *data) { GHashTable *optlist; const char *port; char *line, *jid, *password, *network, *network_free, *host, *host_free; void *free_arg; line = host_free = network_free = NULL; if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS, "xmppconnect", &optlist, &jid, &password)) return NULL; if (*password == '\0') password = g_strdup("\r"); /* we will prompt for password later */ if (*jid == '\0' || password == NULL || *password == '\0' || !xmpp_have_domain(jid)) { cmd_params_free(free_arg); signal_emit("error command", 1, GINT_TO_POINTER(CMDERR_NOT_ENOUGH_PARAMS)); signal_stop(); return NULL; } network = g_hash_table_lookup(optlist, "network"); if (network == NULL || *network == '\0') { char *stripped = xmpp_strip_resource(jid); network = network_free = g_strconcat("xmpp:", stripped, (void *)NULL); g_free(stripped); } host = g_hash_table_lookup(optlist, "host"); if (host == NULL || *host == '\0') host = host_free = xmpp_extract_domain(jid); port = g_hash_table_lookup(optlist, "port"); if (port == NULL) port = "0"; line = g_strdup_printf("%s-xmppnet \"%s\" %s %d \"%s\" \"%s\"", (g_hash_table_lookup(optlist, "ssl") != NULL) ? "-ssl " : "", network, host, atoi(port), password, jid); g_free(network_free); g_free(host_free); cmd_params_free(free_arg); return line; } /* SYNTAX: XMPPCONNECT [-ssl] [-host ] [-port ] * [/] */ static void cmd_xmppconnect(const char *data, SERVER_REC *server, WI_ITEM_REC *item) { char *line, *cmd_line; if ((line = cmd_connect_get_line(data)) == NULL) return; cmd_line = g_strconcat(settings_get_str("cmdchars"), "CONNECT ", line, (void *)NULL); g_free(line); signal_emit("send command", 3, cmd_line, server, item); g_free(cmd_line); } /* SYNTAX: XMPPSERVER [-ssl] [-host ] [-port ] * [/] */ static void cmd_xmppserver(const char *data, SERVER_REC *server, WI_ITEM_REC *item) { char *line, *cmd_line; if ((line = cmd_connect_get_line(data)) == NULL) return; cmd_line = g_strconcat(settings_get_str("cmdchars"), "SERVER ", line, (void *)NULL); g_free(line); signal_emit("send command", 3, cmd_line, server, item); g_free(cmd_line); } static void set_away(XMPP_SERVER_REC *server, const char *data) { char **tmp; const char *reason; int show, priority; if (!IS_XMPP_SERVER(server)) return; priority = settings_get_int("xmpp_priority"); tmp = g_strsplit(data, " ", 2); if (*data == '\0') { show = XMPP_PRESENCE_AVAILABLE; reason = NULL; } else { show = xmpp_get_show(tmp[0]); if (show == XMPP_PRESENCE_AVAILABLE && g_ascii_strcasecmp( xmpp_presence_show[XMPP_PRESENCE_ONLINE], tmp[0]) != 0) { show = xmpp_get_show( settings_get_str("xmpp_default_away_mode")); reason = data; } else reason = tmp[1]; if (show == XMPP_PRESENCE_AWAY) priority = settings_get_int("xmpp_priority_away"); } signal_emit("xmpp set presence", 4, server, show, reason, priority); g_strfreev(tmp); } /* SYNTAX: AWAY [-one | -all] [away|dnd|xa|chat] [] */ static void cmd_away(const char *data, XMPP_SERVER_REC *server) { GHashTable *optlist; char *reason; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS | PARAM_FLAG_GETREST, "away", &optlist, &reason)) return; if (g_hash_table_lookup(optlist, "one") != NULL) set_away(server, reason); else g_slist_foreach(servers, (GFunc)set_away, reason); cmd_params_free(free_arg); } /* SYNTAX: QUOTE */ static void cmd_quote(const char *data, XMPP_SERVER_REC *server) { char *recoded; CMD_XMPP_SERVER(server); if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); g_strstrip((char *)data); if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); signal_emit("xmpp xml out", 2, server, data); recoded = xmpp_recode_out(data); lm_connection_send_raw(server->lmconn, recoded, NULL); g_free(recoded); } /* SYNTAX: ROSTER */ static void cmd_roster(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { CMD_XMPP_SERVER(server); if (*data == '\0') signal_emit("xmpp roster show", 1, server); else command_runsub(xmpp_commands[XMPP_COMMAND_ROSTER], data, server, item); } /* SYNTAX: ROSTER FULL */ static void cmd_roster_full(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { gboolean oldvalue; CMD_XMPP_SERVER(server); oldvalue = settings_get_bool("xmpp_roster_show_offline"); if (!oldvalue) settings_set_bool("xmpp_roster_show_offline", TRUE); signal_emit("xmpp roster show", 1, server); if (!oldvalue) settings_set_bool("xmpp_roster_show_offline", oldvalue); } /* SYNTAX: ROSTER ADD */ static void cmd_roster_add(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; LmMessageNode *query_node, *item_node; GHashTable *optlist; const char *jid; char *jid_recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS, "roster add", &optlist, &jid)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); query_node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster"); jid_recoded = xmpp_recode_out(jid); item_node = lm_message_node_add_child(query_node, "item", NULL); lm_message_node_set_attribute(item_node, "jid", jid_recoded); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); if (g_hash_table_lookup(optlist, "nosub") == NULL) { lmsg = lm_message_new_with_sub_type(jid_recoded, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_SUBSCRIBE); signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); } g_free(jid_recoded); cmd_params_free(free_arg); } /* SYNTAX: ROSTER REMOVE */ static void cmd_roster_remove(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; LmMessageNode *query_node, *item_node; XMPP_ROSTER_USER_REC *user; const char *jid; char *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 1, &jid)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); user = rosters_find_user(server->roster, jid, NULL, NULL); if (user == NULL) { signal_emit("xmpp not in roster", 2, server, jid); goto out; } lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); query_node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster"); item_node = lm_message_node_add_child(query_node, "item", NULL); recoded = xmpp_recode_out(jid); lm_message_node_set_attribute(item_node, "jid", recoded); g_free(recoded); lm_message_node_set_attribute(item_node, "subscription", "remove"); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); out: cmd_params_free(free_arg); } /* SYNTAX: ROSTER NAME [] */ static void cmd_roster_name(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; LmMessageNode *query_node, *item_node; XMPP_ROSTER_USER_REC *user; XMPP_ROSTER_GROUP_REC *group; const char *jid, *name; char *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &jid, &name)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); user = rosters_find_user(server->roster, jid, &group, NULL); if (user == NULL) { signal_emit("xmpp not in roster", 2, server, jid); goto out; } lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); query_node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster"); item_node = lm_message_node_add_child(query_node, "item", NULL); recoded = xmpp_recode_out(jid); lm_message_node_set_attribute(item_node, "jid", recoded); g_free(recoded); if (group->name != NULL) { recoded = xmpp_recode_out(group->name); lm_message_node_add_child(item_node, "group", recoded); g_free(recoded); } if (*name != '\0') { recoded = xmpp_recode_out(name); lm_message_node_set_attribute(item_node, "name", recoded); g_free(recoded); } signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); out: cmd_params_free(free_arg); } /* SYNTAX: ROSTER GROUP [] */ static void cmd_roster_group(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; LmMessageNode *query_node, *item_node; XMPP_ROSTER_USER_REC *user; XMPP_ROSTER_GROUP_REC *group; const char *jid, *group_name; char *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &jid, &group_name)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); user = rosters_find_user(server->roster, jid, &group, NULL); if (user == NULL) { signal_emit("xmpp not in roster", 2, server, jid); goto out; } lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); query_node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster"); item_node = lm_message_node_add_child(query_node, "item", NULL); recoded = xmpp_recode_out(jid); lm_message_node_set_attribute(item_node, "jid", recoded); g_free(recoded); if (*group_name != '\0') { recoded = xmpp_recode_out(group_name); lm_message_node_add_child(item_node, "group", recoded); g_free(recoded); } if (user->name != NULL) { recoded = xmpp_recode_out(user->name); lm_message_node_set_attribute(item_node, "name", recoded); g_free(recoded); } signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); out: cmd_params_free(free_arg); } /* SYNTAX: PRESENCE */ static void cmd_presence(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { CMD_XMPP_SERVER(server); if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); else command_runsub(xmpp_commands[XMPP_COMMAND_PRESENCE], data, server, item); } /* SYNTAX: PRESENCE ACCEPT */ static void cmd_presence_accept(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; const char *jid; char *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 1, &jid)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); recoded = xmpp_recode_out(jid); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_SUBSCRIBED); g_free(recoded); signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); cmd_params_free(free_arg); } /* SYNTAX: PRESENCE DENY */ static void cmd_presence_deny(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; const char *jid; char *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 1, &jid)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); recoded = xmpp_recode_out(jid); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_PRESENCE,LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED); g_free(recoded); signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); cmd_params_free(free_arg); } /* SYNTAX: PRESENCE SUBSCRIBE [] */ static void cmd_presence_subscribe(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; const char *jid, *reason; char *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &jid, &reason)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); recoded = xmpp_recode_out(jid); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_SUBSCRIBE); g_free(recoded); if (*reason != '\0') { recoded = xmpp_recode_out(reason); lm_message_node_add_child(lmsg->node, "status", recoded); g_free(recoded); } signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); cmd_params_free(free_arg); } /* SYNTAX: PRESENCE UNSUBSCRIBE */ static void cmd_presence_unsubscribe(const char *data, XMPP_SERVER_REC *server) { LmMessage *lmsg; const char *jid; char *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 1, &jid)) return; if (*jid == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); recoded = xmpp_recode_out(jid); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE); g_free(recoded); signal_emit("xmpp send presence", 2, server, lmsg); lm_message_unref(lmsg); cmd_params_free(free_arg); } /* SYNTAX: ME */ static void cmd_me(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { const char *target; char *str, *recoded; int type; CMD_XMPP_SERVER(server); if (item == NULL || *data == '\0') return; g_strstrip((char *)data); if (*data == '\0') return; target = window_item_get_target(item); type = IS_CHANNEL(item) ? SEND_TARGET_CHANNEL : SEND_TARGET_NICK; if (type == SEND_TARGET_NICK) signal_emit("message xmpp own_action", 4, server, data, target, SEND_TARGET_NICK); str = g_strconcat("/me ", data, (void *)NULL); recoded = recode_out(SERVER(server), str, target); g_free(str); server->send_message(SERVER(server), target, recoded, type); g_free(recoded); } char * xmpp_get_dest(const char *cmd_dest, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { NICK_REC *nick; char *dest; if (cmd_dest == NULL || *cmd_dest == '\0') return IS_QUERY(item) ? g_strdup(QUERY(item)->name) : g_strconcat(server->jid, "/", server->resource, (void *)NULL); if (IS_CHANNEL(item) && (nick = nicklist_find(CHANNEL(item), cmd_dest)) != NULL) return g_strdup(nick->host); if ((dest = rosters_resolve_name(server, cmd_dest)) != NULL) return dest; return g_strdup(cmd_dest); } void xmpp_commands_init(void) { command_set_options("connect", "+xmppnet"); command_set_options("server add", "-xmppnet"); command_bind("xmppconnect", NULL, (SIGNAL_FUNC)cmd_xmppconnect); command_set_options("xmppconnect", "ssl -network -host @port"); command_bind("xmppserver", NULL, (SIGNAL_FUNC)cmd_xmppserver); command_bind_xmpp("away", NULL, (SIGNAL_FUNC)cmd_away); command_bind_xmpp("quote", NULL, (SIGNAL_FUNC)cmd_quote); command_bind_xmpp("roster", NULL, (SIGNAL_FUNC)cmd_roster); command_bind_xmpp("roster full", NULL, (SIGNAL_FUNC)cmd_roster_full); command_bind_xmpp("roster add", NULL, (SIGNAL_FUNC)cmd_roster_add); command_set_options("roster add", "nosub"); command_bind_xmpp("roster remove", NULL, (SIGNAL_FUNC)cmd_roster_remove); command_bind_xmpp("roster name", NULL, (SIGNAL_FUNC)cmd_roster_name); command_bind_xmpp("roster group", NULL, (SIGNAL_FUNC)cmd_roster_group); command_bind_xmpp("presence", NULL, (SIGNAL_FUNC)cmd_presence); command_bind_xmpp("presence accept", NULL, (SIGNAL_FUNC)cmd_presence_accept); command_bind_xmpp("presence deny", NULL, (SIGNAL_FUNC)cmd_presence_deny); command_bind_xmpp("presence subscribe", NULL, (SIGNAL_FUNC)cmd_presence_subscribe); command_bind_xmpp("presence unsubscribe", NULL, (SIGNAL_FUNC)cmd_presence_unsubscribe); command_bind_xmpp("me", NULL, (SIGNAL_FUNC)cmd_me); settings_add_str("xmpp", "xmpp_default_away_mode", "away"); } void xmpp_commands_deinit(void) { command_unbind("xmppconnect", (SIGNAL_FUNC)cmd_xmppconnect); command_unbind("xmppserver", (SIGNAL_FUNC)cmd_xmppserver); command_unbind("away", (SIGNAL_FUNC)cmd_away); command_unbind("quote", (SIGNAL_FUNC)cmd_quote); command_unbind("roster", (SIGNAL_FUNC)cmd_roster); command_unbind("roster full", (SIGNAL_FUNC)cmd_roster_full); command_unbind("roster add", (SIGNAL_FUNC)cmd_roster_add); command_unbind("roster remove", (SIGNAL_FUNC)cmd_roster_remove); command_unbind("roster name", (SIGNAL_FUNC)cmd_roster_name); command_unbind("roster group", (SIGNAL_FUNC)cmd_roster_group); command_unbind("presence", (SIGNAL_FUNC)cmd_presence); command_unbind("presence accept", (SIGNAL_FUNC)cmd_presence_accept); command_unbind("presence deny", (SIGNAL_FUNC)cmd_presence_deny); command_unbind("presence subscribe", (SIGNAL_FUNC)cmd_presence_subscribe); command_unbind("presence unsubscribe", (SIGNAL_FUNC)cmd_presence_unsubscribe); command_unbind("me", (SIGNAL_FUNC)cmd_me); } src/core/xep/0000755000175000017500000000000012261362415011175 5ustar fsfssrc/core/xep/muc-nicklist.c0000644000175000017500000001367112261362415013753 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "signals.h" #include "rosters.h" #include "muc-nicklist.h" const char *xmpp_nicklist_affiliation[] = { "none", "owner", "admin", "member", "outcast", NULL }; const char *xmpp_nicklist_role[] = { "none", "moderator", "participant", "visitor", NULL }; XMPP_NICK_REC * xmpp_nicklist_insert(MUC_REC *channel, const char *nickname, const char *full_jid) { XMPP_NICK_REC *rec; g_return_val_if_fail(IS_MUC(channel), NULL); g_return_val_if_fail(nickname != NULL, NULL); rec = g_new0(XMPP_NICK_REC, 1); rec->nick = g_strdup(nickname); rec->host = (full_jid != NULL) ? g_strdup(full_jid) : g_strconcat(channel->name, "/", rec->nick, (void *)NULL); rec->show = XMPP_PRESENCE_AVAILABLE; rec->status = NULL; rec->affiliation = XMPP_NICKLIST_AFFILIATION_NONE; rec->role = XMPP_NICKLIST_ROLE_NONE; nicklist_insert(CHANNEL(channel), (NICK_REC *)rec); return rec; } static void nick_hash_add(CHANNEL_REC *channel, NICK_REC *nick) { NICK_REC *list; nick->next = NULL; list = g_hash_table_lookup(channel->nicks, nick->nick); if (list == NULL) g_hash_table_insert(channel->nicks, nick->nick, nick); else { /* multiple nicks with same name */ while (list->next != NULL) list = list->next; list->next = nick; } /* move our own nick to beginning of the nick list.. */ if (nick == channel->ownnick) nicklist_set_own(channel, nick); } static void nick_hash_remove(CHANNEL_REC *channel, NICK_REC *nick) { NICK_REC *list; list = g_hash_table_lookup(channel->nicks, nick->nick); if (list == NULL) return; if (list == nick || list->next == NULL) { g_hash_table_remove(channel->nicks, nick->nick); if (list->next != NULL) g_hash_table_insert(channel->nicks, nick->next->nick, nick->next); } else { while (list->next != nick) list = list->next; list->next = nick->next; } } void xmpp_nicklist_rename(MUC_REC *channel, XMPP_NICK_REC *nick, const char *oldnick, const char *newnick) { g_return_if_fail(IS_MUC(channel)); g_return_if_fail(IS_XMPP_NICK(nick)); g_return_if_fail(oldnick != NULL); g_return_if_fail(newnick != NULL); /* remove old nick from hash table */ nick_hash_remove(CHANNEL(channel), NICK(nick)); g_free(nick->nick); nick->nick = g_strdup(newnick); /* add new nick to hash table */ nick_hash_add(CHANNEL(channel), NICK(nick)); signal_emit("nicklist changed", 3, channel, nick, oldnick); if (strcmp(oldnick, channel->nick) == 0) { nicklist_set_own(CHANNEL(channel), NICK(nick)); g_free(channel->nick); channel->nick = g_strdup(newnick); } } int xmpp_nicklist_get_affiliation(const char *affiliation) { if (affiliation != NULL) { if (g_ascii_strcasecmp(affiliation, xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_OWNER]) == 0) return XMPP_NICKLIST_AFFILIATION_OWNER; else if (g_ascii_strcasecmp(affiliation, xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_ADMIN]) == 0) return XMPP_NICKLIST_AFFILIATION_ADMIN; else if (g_ascii_strcasecmp(affiliation, xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_MEMBER]) == 0) return XMPP_NICKLIST_AFFILIATION_MEMBER; else if (g_ascii_strcasecmp(affiliation, xmpp_nicklist_affiliation[XMPP_NICKLIST_AFFILIATION_OUTCAST]) == 0) return XMPP_NICKLIST_AFFILIATION_OUTCAST; } return XMPP_NICKLIST_AFFILIATION_NONE; } int xmpp_nicklist_get_role(const char *role) { if (role != NULL) { if (g_ascii_strcasecmp(role, xmpp_nicklist_role[XMPP_NICKLIST_ROLE_MODERATOR]) == 0) return XMPP_NICKLIST_ROLE_MODERATOR; else if (g_ascii_strcasecmp(role, xmpp_nicklist_role[XMPP_NICKLIST_ROLE_PARTICIPANT]) == 0) return XMPP_NICKLIST_ROLE_PARTICIPANT; else if (g_ascii_strcasecmp(role, xmpp_nicklist_role[XMPP_NICKLIST_ROLE_VISITOR]) == 0) return XMPP_NICKLIST_ROLE_VISITOR; } return XMPP_NICKLIST_ROLE_NONE; } gboolean xmpp_nicklist_modes_changed(XMPP_NICK_REC *nick, int affiliation, int role) { g_return_val_if_fail(IS_XMPP_NICK(nick), FALSE); return nick->affiliation != affiliation || nick->role != role; } void xmpp_nicklist_set_modes(XMPP_NICK_REC *nick, int affiliation, int role) { g_return_if_fail(IS_XMPP_NICK(nick)); nick->affiliation = affiliation; nick->role = role; switch (affiliation) { case XMPP_NICKLIST_AFFILIATION_OWNER: nick->prefixes[0] = '&'; nick->prefixes[1] = '\0'; nick->op = TRUE; break; case XMPP_NICKLIST_AFFILIATION_ADMIN: nick->prefixes[0] = '\0'; nick->op = TRUE; break; default: nick->prefixes[0] = '\0'; nick->op = FALSE; } switch (role) { case XMPP_NICKLIST_ROLE_MODERATOR: nick->voice = TRUE; nick->halfop = TRUE; break; case XMPP_NICKLIST_ROLE_PARTICIPANT: nick->halfop = FALSE; nick->voice = TRUE; break; default: nick->halfop = FALSE; nick->voice = FALSE; } } void xmpp_nicklist_set_presence(XMPP_NICK_REC *nick, int show, const char *status) { g_return_if_fail(IS_XMPP_NICK(nick)); nick->show = show; g_free(nick->status); nick->status = g_strdup(status); } static void sig_nicklist_remove(MUC_REC *channel, XMPP_NICK_REC *nick) { if (!IS_MUC(channel) || !IS_XMPP_NICK(nick)) return; g_free(nick->status); } void muc_nicklist_init(void) { signal_add("nicklist remove", sig_nicklist_remove); } void muc_nicklist_deinit(void) { signal_remove("nicklist remove", sig_nicklist_remove); } src/core/xep/registration.h0000644000175000017500000000104112261362415014054 0ustar fsfs#ifndef __REGISTRATION_H #define __REGISTRATION_H enum { REGISTRATION_ERROR_UNAUTHORIZED = 401, REGISTRATION_ERROR_UNAUTHORIZED_REG = 407, REGISTRATION_ERROR_UNIMPLEMENTED = 501, REGISTRATION_ERROR_UNAVAILABLE = 503, REGISTRATION_ERROR_CONFLICT = 409, REGISTRATION_ERROR_TIMEOUT = 408, REGISTRATION_ERROR_TIMEOUT_SERVER = 504, REGISTRATION_ERROR_CONNECTION = -3, REGISTRATION_ERROR_INFO = -2, REGISTRATION_ERROR_UNKNOWN = -1, }; __BEGIN_DECLS void registration_init(void); void registration_deinit(void); __END_DECLS #endif src/core/xep/version.h0000644000175000017500000000017712261362415013040 0ustar fsfs#ifndef __VERSION_H #define __VERSION_H __BEGIN_DECLS void version_init(void); void version_deinit(void); __END_DECLS #endif src/core/xep/composing.h0000644000175000017500000000020712261362415013343 0ustar fsfs#ifndef __COMPOSING_H #define __COMPOSING_H __BEGIN_DECLS void composing_init(void); void composing_deinit(void); __END_DECLS #endif src/core/xep/oob.h0000644000175000017500000000015712261362415012130 0ustar fsfs#ifndef __OOB_H #define __OOB_H __BEGIN_DECLS void oob_init(void); void oob_deinit(void); __END_DECLS #endif src/core/xep/muc-reconnect.h0000644000175000017500000000022712261362415014111 0ustar fsfs#ifndef __MUC_RECONNECT_H #define __MUC_RECONNECT_H __BEGIN_DECLS void muc_reconnect_init(void); void muc_reconnect_deinit(void); __END_DECLS #endif src/core/xep/vcard.h0000644000175000017500000000016712261362415012451 0ustar fsfs#ifndef __VCARD_H #define __VCARD_H __BEGIN_DECLS void vcard_init(void); void vcard_deinit(void); __END_DECLS #endif src/core/xep/tool_datalist.h0000644000175000017500000000134212261362415014210 0ustar fsfs#ifndef __TOOL_DATALIST_H #define __TOOL_DATALIST_H #include "xmpp-servers.h" typedef struct datalist_rec { XMPP_SERVER_REC *server; char *jid; void *data; } DATALIST_REC; typedef struct datalist_first { GSList *list; void (*freedata_func)(DATALIST_REC *); } DATALIST; __BEGIN_DECLS DATALIST *datalist_new(void (*)(DATALIST_REC *)); void datalist_destroy(DATALIST *); DATALIST_REC *datalist_find(DATALIST *, XMPP_SERVER_REC *, const char *); DATALIST_REC *datalist_add(DATALIST *, XMPP_SERVER_REC *, const char *, void *); void datalist_free(DATALIST *, DATALIST_REC *); void datalist_remove(DATALIST *, XMPP_SERVER_REC *, const char *); void datalist_cleanup(DATALIST *, XMPP_SERVER_REC *); __END_DECLS #endif src/core/xep/composing.c0000644000175000017500000001347512261362415013351 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0022: Message Events */ #include #include "module.h" #include "signals.h" #include "xmpp-servers.h" #include "xmpp-queries.h" #include "tools.h" #include "tool_datalist.h" #include "disco.h" #define XMLNS_EVENT "jabber:x:event" static DATALIST *composings; #define send_start(server, dest, id) \ send_composing_event(server, dest, id, TRUE) #define send_stop(server, dest, id) \ send_composing_event(server, dest, id, FALSE) static void send_composing_event(XMPP_SERVER_REC *server, const char *dest, const char *id, gboolean composing) { LmMessage *lmsg; LmMessageNode *node; char *recoded; recoded = xmpp_recode_out(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_CHAT); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "x", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_EVENT); if (composing) lm_message_node_add_child(node, "composing", NULL); if (id != NULL) lm_message_node_add_child(node, "id", id); signal_emit("xmpp send message", 2, server, lmsg); lm_message_unref(lmsg); } static void sig_composing_start(XMPP_SERVER_REC *server, const char *dest) { DATALIST_REC *rec; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(dest != NULL); if ((rec = datalist_find(composings, server, dest)) != NULL) send_start(server, dest, rec->data); } static void sig_composing_stop(XMPP_SERVER_REC *server, const char *dest) { DATALIST_REC *rec; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(dest != NULL); if ((rec = datalist_find(composings, server, dest)) != NULL) send_stop(server, dest, rec->data); } static void sig_composing_show(XMPP_SERVER_REC *server, const char *dest) { XMPP_QUERY_REC *query; if ((query = xmpp_query_find(server, dest)) != NULL) query->composing_visible = TRUE; } static void sig_composing_hide(XMPP_SERVER_REC *server, const char *dest) { XMPP_QUERY_REC *query; if ((query = xmpp_query_find(server, dest)) != NULL) query->composing_visible = FALSE; } static void sig_recv_message(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node; if ((type != LM_MESSAGE_SUB_TYPE_NOT_SET && type != LM_MESSAGE_SUB_TYPE_HEADLINE && type != LM_MESSAGE_SUB_TYPE_NORMAL && type != LM_MESSAGE_SUB_TYPE_CHAT) || server->ischannel(SERVER(server), from)) return; node = lm_find_node(lmsg->node, "x", XMLNS, XMLNS_EVENT); if (node == NULL) { signal_emit("xmpp composing hide", 2, server, from); return; } if (lm_message_node_get_child(lmsg->node, "body") != NULL || lm_message_node_get_child(lmsg->node, "subject") != NULL) { if (lm_message_node_get_child(node, "composing") != NULL) datalist_add(composings, server, from, g_strdup(id)); else datalist_remove(composings, server, from); signal_emit("xmpp composing hide", 2, server, from); } else { if (lm_message_node_get_child(node, "composing") != NULL) signal_emit("xmpp composing show", 2, server, from); else signal_emit("xmpp composing hide", 2, server, from); } } static void sig_send_message(XMPP_SERVER_REC *server, LmMessage *lmsg) { LmMessageNode *node; LmMessageSubType type; type = lm_message_get_sub_type(lmsg); if ((type != LM_MESSAGE_SUB_TYPE_NOT_SET && type != LM_MESSAGE_SUB_TYPE_HEADLINE && type != LM_MESSAGE_SUB_TYPE_NORMAL && type != LM_MESSAGE_SUB_TYPE_CHAT) || (lm_message_node_get_child(lmsg->node, "body") == NULL && lm_message_node_get_child(lmsg->node, "subject") == NULL)) return; /* request composing events */ node = lm_message_node_add_child(lmsg->node, "x", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_EVENT); lm_message_node_add_child(node, "composing", NULL); } static void sig_offline(XMPP_SERVER_REC *server, const char *jid) { g_return_if_fail(IS_XMPP_SERVER(server)); datalist_remove(composings, server, jid); } static void sig_disconnected(XMPP_SERVER_REC *server) { if (IS_XMPP_SERVER(server)) datalist_cleanup(composings, server); } static void freedata_func(DATALIST_REC *rec) { g_free(rec->data); } void composing_init(void) { composings = datalist_new(freedata_func); disco_add_feature(XMLNS_EVENT); signal_add("xmpp composing start", sig_composing_start); signal_add("xmpp composing stop", sig_composing_stop); signal_add("xmpp composing show", sig_composing_show); signal_add("xmpp composing hide", sig_composing_hide); signal_add("xmpp recv message", sig_recv_message); signal_add("xmpp send message", sig_send_message); signal_add("xmpp presence offline", sig_offline); signal_add("server disconnected", sig_disconnected); } void composing_deinit(void) { signal_remove("xmpp composing start", sig_composing_start); signal_remove("xmpp composing stop", sig_composing_stop); signal_remove("xmpp composing show", sig_composing_show); signal_remove("xmpp composing hide", sig_composing_hide); signal_remove("xmpp recv message", sig_recv_message); signal_remove("xmpp send message", sig_send_message); signal_remove("xmpp presence offline", sig_offline); signal_remove("server disconnected", sig_disconnected); datalist_destroy(composings); } src/core/xep/disco.c0000644000175000017500000001126012261362415012442 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* XEP-0030: Service Discovery */ #include #include "module.h" #include "signals.h" #include "xmpp-servers.h" #include "tools.h" #include "disco.h" #define XMLNS_DISCO "http://jabber.org/protocol/disco#info" static GSList *my_features; void disco_add_feature(char *feature) { g_return_if_fail(feature != NULL && *feature != '\0'); my_features = g_slist_insert_sorted(my_features, feature, (GCompareFunc)strcmp); } gboolean disco_have_feature(GSList *list, const char *feature) { GSList *tmp; for (tmp = list; tmp != NULL; tmp = tmp->next) if (strcmp(feature, tmp->data) == 0) return TRUE; return FALSE; } static void cleanup_features(GSList *list) { GSList *tmp, *next; for (tmp = list; tmp != NULL; tmp = next) { next = tmp->next; g_free(tmp->data); list = g_slist_remove(list, tmp->data); } } void disco_request(XMPP_SERVER_REC *server, const char *dest) { LmMessage *lmsg; LmMessageNode *node; char *recoded; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(dest != NULL && dest != '\0'); recoded = xmpp_recode_out(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_DISCO); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } static void send_disco(XMPP_SERVER_REC *server, const char *dest) { LmMessage *lmsg; LmMessageNode *node, *child; GSList *tmp; char *recoded; recoded = xmpp_recode_out(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_RESULT); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_DISCO); child = lm_message_node_add_child(node, "identity", NULL); lm_message_node_set_attribute(child, "category", "client"); lm_message_node_set_attribute(child, "type", "console"); lm_message_node_set_attribute(child, "name", IRSSI_XMPP_PACKAGE); for (tmp = my_features; tmp != NULL; tmp = tmp->next) { child = lm_message_node_add_child(node, "feature", NULL); lm_message_node_set_attribute(child, "var", tmp->data); } signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } static void sig_recv_iq(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node; GSList *features; if (type == LM_MESSAGE_SUB_TYPE_RESULT) { node = lm_find_node(lmsg->node, "query", XMLNS, XMLNS_DISCO); if (node == NULL) return; features = NULL; for (node = node->children; node != NULL; node = node->next) { if (strcmp(node->name, "feature") == 0) { features = g_slist_prepend(features, xmpp_recode_in( lm_message_node_get_attribute(node, "var"))); } } signal_emit("xmpp features", 3, server, from, features); if (strcmp(from, server->domain) == 0) { cleanup_features(server->server_features); server->server_features = features; signal_emit("xmpp server features", 1, server); } else cleanup_features(features); } else if (type == LM_MESSAGE_SUB_TYPE_GET) { node = lm_find_node(lmsg->node, "query", XMLNS, XMLNS_DISCO); if (node != NULL) send_disco(server, from); } } static void sig_connected(XMPP_SERVER_REC *server) { if (IS_XMPP_SERVER(server)) disco_request(server, server->domain); } static void sig_disconnected(XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER(server)) return; cleanup_features(server->server_features); server->server_features = NULL; } void disco_init(void) { my_features = NULL; disco_add_feature(XMLNS_DISCO); signal_add("server connected", sig_connected); signal_add("server disconnected", sig_disconnected); signal_add("xmpp recv iq", sig_recv_iq); } void disco_deinit(void) { signal_remove("server connected", sig_connected); signal_remove("server disconnected", sig_disconnected); signal_remove("xmpp recv iq", sig_recv_iq); g_slist_free(my_features); } src/core/xep/ping.h0000644000175000017500000000025212261362415012302 0ustar fsfs#ifndef __PING_H #define __PING_H __BEGIN_DECLS void xmpp_ping_send(XMPP_SERVER_REC *, const char *); void ping_init(void); void ping_deinit(void); __END_DECLS #endif src/core/xep/muc.h0000644000175000017500000000304612261362415012135 0ustar fsfs#ifndef __MUC_H #define __MUC_H #include "channels.h" #include "channels-setup.h" #include "xmpp-servers.h" #include "tools.h" #define XMLNS_MUC "http://jabber.org/protocol/muc" #define XMLNS_MUC_USER "http://jabber.org/protocol/muc#user" #define muc_extract_nick(jid) \ xmpp_extract_resource(jid) #define muc_extract_channel(jid) \ xmpp_strip_resource(jid) #define MUC_SETUP(chansetup) \ PROTO_CHECK_CAST(CHANNEL_SETUP(chansetup), CHANNEL_SETUP_REC, chat_type, "XMPP") #define IS_MUC_SETUP(chansetup) \ (MUC_SETUP(chansetup) ? TRUE : FALSE) /* Returns MUC_REC if it's XMPP channel, NULL if it isn't. */ #define MUC(channel) \ PROTO_CHECK_CAST(CHANNEL(channel), MUC_REC, chat_type, "XMPP") #define IS_MUC(channel) \ (MUC(channel) ? TRUE : FALSE) #define muc_find(server, name) \ MUC(channel_find(SERVER(server), name)) #define STRUCT_SERVER_REC XMPP_SERVER_REC struct _MUC_REC { #include "channel-rec.h" char *nick; }; enum { MUC_ERROR_UNKNOWN, MUC_ERROR_PASSWORD_INVALID_OR_MISSING = 401, MUC_ERROR_USER_BANNED = 403, MUC_ERROR_ROOM_NOT_FOUND = 404, MUC_ERROR_ROOM_CREATION_RESTRICTED = 405, MUC_ERROR_USE_RESERVED_ROOM_NICK = 406, MUC_ERROR_NOT_ON_MEMBERS_LIST = 407, MUC_ERROR_NICK_IN_USE = 409, MUC_ERROR_MAXIMUM_USERS_REACHED = 503, }; __BEGIN_DECLS void muc_join(XMPP_SERVER_REC *, const char *, gboolean); void muc_part(MUC_REC *, const char *); void muc_nick(MUC_REC *, const char *); MUC_REC *get_muc(XMPP_SERVER_REC *, const char *); void muc_init(void); void muc_deinit(void); __END_DECLS #endif src/core/xep/disco.h0000644000175000017500000000043312261362415012447 0ustar fsfs#ifndef __DISCO_H #define __DISCO_H __BEGIN_DECLS void disco_add_feature(char *); gboolean disco_have_feature(GSList *, const char *); void disco_request(XMPP_SERVER_REC *, const char *); void disco_init(void); void disco_deinit(void); __END_DECLS #define XMLNS "xmlns" #endif src/core/xep/xep.h0000644000175000017500000000015712261362415012145 0ustar fsfs#ifndef __XEP_H #define __XEP_H __BEGIN_DECLS void xep_init(void); void xep_deinit(void); __END_DECLS #endif src/core/xep/ping.c0000644000175000017500000001427512261362415012307 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0199: XMPP Ping * and lagmeter */ #include #include #include "module.h" #include "misc.h" #include "settings.h" #include "signals.h" #include "xmpp-servers.h" #include "xmpp-commands.h" #include "tool_datalist.h" #include "disco.h" #include "tools.h" #define XMLNS_PING "urn:xmpp:ping" struct ping_data { char *id; GTimeVal time; }; static int timeout_tag; static GSList *supported_servers; static DATALIST *pings; static void request_ping(XMPP_SERVER_REC *server, const char *dest) { struct ping_data *pd; LmMessage *lmsg; LmMessageNode *node; char *recoded; recoded = xmpp_recode_in(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "ping", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_PING); if (strcmp(dest, server->domain) == 0) { g_free(server->ping_id); server->ping_id = g_strdup(lm_message_node_get_attribute(lmsg->node, "id")); g_get_current_time(&server->lag_sent); server->lag_last_check = time(NULL); } else { pd = g_new0(struct ping_data, 1); pd->id = g_strdup(lm_message_node_get_attribute(lmsg->node, "id")); g_get_current_time(&pd->time); datalist_add(pings, server, dest, pd); } signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } static void send_ping(XMPP_SERVER_REC *server, const char *dest, const char *id) { LmMessage *lmsg; char *recoded; recoded = xmpp_recode_in(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_RESULT); g_free(recoded); if (id != NULL) lm_message_node_set_attribute(lmsg->node, "id", id); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } static void sig_recv_iq(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { DATALIST_REC *rec; LmMessageNode *node; GTimeVal now; struct ping_data *pd; if (type == LM_MESSAGE_SUB_TYPE_RESULT) { /* pong response from server of our ping */ if (server->ping_id != NULL && (*from == '\0' || strcmp(from, server->domain) == 0) && strcmp(id, server->ping_id) == 0) { g_get_current_time(&now); server->lag = (int)get_timeval_diff(&now, &server->lag_sent); memset(&server->lag_sent, 0, sizeof(server->lag_sent)); g_free_and_null(server->ping_id); signal_emit("server lag", 1, server); } else if (lmsg->node->children == NULL && (rec = datalist_find(pings, server, from)) != NULL) { pd = rec->data; if (strcmp(id, pd->id) == 0) { g_get_current_time(&now); signal_emit("xmpp ping", 3, server, from, get_timeval_diff(&now, &pd->time)); } } } else if (type == LM_MESSAGE_SUB_TYPE_GET) { node = lm_find_node(lmsg->node, "ping", XMLNS, XMLNS_PING); if (node == NULL) node = lm_find_node(lmsg->node, "query", XMLNS, XMLNS_PING); if (node != NULL) send_ping(server, from, lm_message_node_get_attribute(lmsg->node, "id")); } } static void sig_server_features(XMPP_SERVER_REC *server) { if (disco_have_feature(server->server_features, XMLNS_PING)) supported_servers = g_slist_prepend(supported_servers, server); } static void sig_disconnected(XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER(server)) return; supported_servers = g_slist_remove(supported_servers, server); datalist_cleanup(pings, server); } static int check_ping_func(void) { GSList *tmp; XMPP_SERVER_REC *server; time_t now; int lag_check_time, max_lag; lag_check_time = settings_get_time("lag_check_time")/1000; max_lag = settings_get_time("lag_max_before_disconnect")/1000; if (lag_check_time <= 0) return 1; now = time(NULL); for (tmp = supported_servers; tmp != NULL; tmp = tmp->next) { server = XMPP_SERVER(tmp->data); if (server->lag_sent.tv_sec != 0) { /* waiting for lag reply */ if (max_lag > 1 && (now - server->lag_sent.tv_sec) > max_lag) { /* too much lag - disconnect */ signal_emit("server lag disconnect", 1, server); server->connection_lost = TRUE; server_disconnect(SERVER(server)); } } else if ((server->lag_last_check + lag_check_time) < now && server->connected) { /* no commands in buffer - get the lag */ request_ping(server, server->domain); } } return 1; } /* SYNTAX: PING [[[/]]|[data)->id); g_free(rec->data); } void ping_init(void) { supported_servers = NULL; pings = datalist_new(freedata_func); disco_add_feature(XMLNS_PING); signal_add("xmpp recv iq", sig_recv_iq); signal_add("xmpp server features", sig_server_features); signal_add("server disconnected", sig_disconnected); command_bind_xmpp("ping", NULL, (SIGNAL_FUNC)cmd_ping); timeout_tag = g_timeout_add(1000, (GSourceFunc)check_ping_func, NULL); } void ping_deinit(void) { g_source_remove(timeout_tag); signal_remove("xmpp recv iq", sig_recv_iq); signal_remove("xmpp server features", sig_server_features); signal_remove("server disconnected", sig_disconnected); command_unbind("ping", (SIGNAL_FUNC)cmd_ping); g_slist_free(supported_servers); datalist_destroy(pings); } src/core/xep/chatstates.c0000644000175000017500000000350012261362415013502 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0085: Chat State Notifications */ #include "module.h" #include "signals.h" #include "xmpp-servers.h" #include "disco.h" #define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" static void sig_recv_message(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { if ((type != LM_MESSAGE_SUB_TYPE_NOT_SET && type != LM_MESSAGE_SUB_TYPE_HEADLINE && type != LM_MESSAGE_SUB_TYPE_NORMAL && type != LM_MESSAGE_SUB_TYPE_CHAT) || server->ischannel(SERVER(server), from)) return; if (lm_find_node(lmsg->node, "composing", XMLNS, XMLNS_CHATSTATES) != NULL) { signal_emit("xmpp composing show", 2, server, from); } else if (lm_find_node(lmsg->node, "active", XMLNS, XMLNS_CHATSTATES) != NULL || lm_find_node(lmsg->node, "paused", XMLNS, XMLNS_CHATSTATES) != NULL) signal_emit("xmpp composing hide", 2, server, from); } void chatstates_init(void) { disco_add_feature(XMLNS_CHATSTATES); signal_add("xmpp recv message", sig_recv_message); } void chatstates_deinit(void) { signal_remove("xmpp recv message", sig_recv_message); } src/core/xep/muc-nicklist.h0000644000175000017500000000273312261362415013755 0ustar fsfs#ifndef __MUC_NICKLIST_H #define __MUC_NICKLIST_H #include "nicklist.h" #include "muc.h" /* Returns XMPP_NICK_REC if it's XMPP channel, NULL if it isn't. */ #define XMPP_NICK(nick) \ PROTO_CHECK_CAST(NICK(nick), XMPP_NICK_REC, chat_type, "XMPP") #define IS_XMPP_NICK(nick) \ (XMPP_NICK(nick) ? TRUE : FALSE) #define xmpp_nicklist_find(channel, name) \ XMPP_NICK(nicklist_find(CHANNEL(channel), name)) struct _XMPP_NICK_REC { #include "nick-rec.h" int show; char *status; int affiliation; int role; }; enum { XMPP_NICKLIST_AFFILIATION_NONE, XMPP_NICKLIST_AFFILIATION_OWNER, XMPP_NICKLIST_AFFILIATION_ADMIN, XMPP_NICKLIST_AFFILIATION_MEMBER, XMPP_NICKLIST_AFFILIATION_OUTCAST }; extern const char *xmpp_nicklist_affiliation[]; enum { XMPP_NICKLIST_ROLE_NONE, XMPP_NICKLIST_ROLE_MODERATOR, XMPP_NICKLIST_ROLE_PARTICIPANT, XMPP_NICKLIST_ROLE_VISITOR }; extern const char *xmpp_nicklist_role[]; __BEGIN_DECLS XMPP_NICK_REC *xmpp_nicklist_insert(MUC_REC *, const char *, const char *); void xmpp_nicklist_rename(MUC_REC *, XMPP_NICK_REC *, const char *, const char *); int xmpp_nicklist_get_affiliation(const char *); int xmpp_nicklist_get_role(const char *); gboolean xmpp_nicklist_modes_changed(XMPP_NICK_REC *, int, int); void xmpp_nicklist_set_modes(XMPP_NICK_REC *, int, int); void xmpp_nicklist_set_presence(XMPP_NICK_REC *, int, const char *); void muc_nicklist_init(void); void muc_nicklist_deinit(void); __END_DECLS #endif src/core/xep/muc-commands.h0000644000175000017500000000022312261362415013726 0ustar fsfs#ifndef __MUC_COMMANDS_H #define __MUC_COMMANDS_H __BEGIN_DECLS void muc_commands_init(void); void muc_commands_deinit(void); __END_DECLS #endif src/core/xep/tool_datalist.c0000644000175000017500000000461012261362415014204 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "tool_datalist.h" DATALIST_REC * datalist_find(DATALIST *dl, XMPP_SERVER_REC *server, const char *jid) { GSList *tmp; DATALIST_REC *rec; for (tmp = dl->list; tmp != NULL; tmp = tmp->next) { rec = tmp->data; if (rec->server == server && strcmp(rec->jid, jid) == 0) return rec; } return NULL; } DATALIST_REC * datalist_add(DATALIST *dl, XMPP_SERVER_REC *server, const char *jid, void *data) { DATALIST_REC *rec; if ((rec = datalist_find(dl, server, jid)) != NULL) { dl->freedata_func(rec); rec->data = data; } else { rec = g_new0(DATALIST_REC, 1); rec->server = server; rec->jid = g_strdup(jid); rec->data = data; dl->list = g_slist_prepend(dl->list, rec); } return rec; } void datalist_free(DATALIST *dl, DATALIST_REC *rec) { dl->list = g_slist_remove(dl->list, rec); g_free(rec->jid); dl->freedata_func(rec); g_free(rec); } void datalist_remove(DATALIST *dl, XMPP_SERVER_REC *server, const char *jid) { DATALIST_REC *rec; if ((rec = datalist_find(dl, server, jid)) != NULL) datalist_free(dl, rec); } void datalist_cleanup(DATALIST *dl, XMPP_SERVER_REC *server) { GSList *tmp, *next; DATALIST_REC *rec; for (tmp = dl->list; tmp != NULL; tmp = next) { next = tmp->next; rec = tmp->data; if (server == NULL || rec->server == server) datalist_free(dl, rec); } } static void dummy_freedata_func(DATALIST_REC *rec) { } DATALIST * datalist_new(void (*freedata_func)(DATALIST_REC *)) { DATALIST *dl; dl = g_new0(DATALIST, 1); dl->list = NULL; dl->freedata_func = freedata_func == NULL ? dummy_freedata_func : freedata_func; return dl; } void datalist_destroy(DATALIST *dl) { datalist_cleanup(dl, NULL); g_free(dl); } src/core/xep/oob.c0000644000175000017500000000403012261362415012115 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0066: Out of Band Data */ #include "module.h" #include "signals.h" #include "xmpp-servers.h" #include "tools.h" #include "disco.h" #define XMLNS_OOB_X "jabber:x:oob" #define XMLNS_OOB_IQ "jabber:iq:oob" static void sig_recv_x(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node, *child; const char *url, *desc; char *url_recoded, *desc_recoded, *str; node = lm_find_node(lmsg->node, "x", XMLNS, XMLNS_OOB_X); if (node != NULL) { child = lm_message_node_get_child(node, "url"); if (child == NULL || child->value == NULL) return; url = child->value; child = lm_message_node_get_child(node, "desc"); desc = child != NULL ? child->value : NULL; url_recoded = xmpp_recode_in(url); if (desc != NULL) { desc_recoded = xmpp_recode_in(desc); str = g_strconcat(desc_recoded, ": ", url_recoded, (void *)NULL); g_free(url_recoded); g_free(desc_recoded); } else str = url_recoded; signal_emit("message private", 4, server, str, from, from); g_free(str); } } void oob_init(void) { disco_add_feature(XMLNS_OOB_X); signal_add("xmpp recv message", sig_recv_x); signal_add("xmpp recv presence", sig_recv_x); } void oob_deinit(void) { signal_remove("xmpp recv message", sig_recv_x); signal_remove("xmpp recv presence", sig_recv_x); } src/core/xep/muc-commands.c0000644000175000017500000001205512261362415013727 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include "module.h" #include "settings.h" #include "signals.h" #include "window-item-def.h" #include "xmpp-servers.h" #include "xmpp-commands.h" #include "tools.h" #include "rosters-tools.h" #include "muc.h" /* SYNTAX: INVITE [/]| [] */ static void cmd_invite(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { MUC_REC *channel; LmMessage *lmsg; LmMessageNode *node, *invite_node; GHashTable *optlist; char *channame, *dest, *jid, *recoded; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS, "xmppinvite", &optlist, &dest, &channame)) return; if (*dest == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); if (*channame == '\0' || g_ascii_strcasecmp(channame, "*") == 0) { if (!IS_MUC(item)) cmd_param_error(CMDERR_NOT_JOINED); channame = MUC(item)->name; } if ((channel = muc_find(server, channame)) == NULL) cmd_param_error(CMDERR_NOT_JOINED); if ((jid = rosters_resolve_name(server, dest)) != NULL) dest = jid; recoded = xmpp_recode_out(channame); lmsg = lm_message_new(recoded, LM_MESSAGE_TYPE_MESSAGE); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "x", NULL); lm_message_node_set_attribute(node, "xmlns", XMLNS_MUC_USER); invite_node = lm_message_node_add_child(node, "invite", NULL); recoded = xmpp_recode_out(dest); lm_message_node_set_attribute(invite_node, "to", recoded); g_free(recoded); signal_emit("xmpp send message", 2, server, lmsg); lm_message_unref(lmsg); g_free(jid); cmd_params_free(free_arg); } /* SYNTAX: PART [] */ static void cmd_part(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { MUC_REC *channel; char *channame, *reason; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTCHAN, item, &channame, &reason)) return; if (*channame == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); if ((channel = muc_find(server, channame)) == NULL) cmd_param_error(CMDERR_NOT_JOINED); if (*reason == '\0') reason = (char *)settings_get_str("part_message"); muc_part(channel, reason); cmd_params_free(free_arg); } /* SYNTAX: NICK [] */ static void cmd_nick(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { MUC_REC *channel; char *channame, *nick; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTCHAN, item, &channame, &nick)) return; if (*channame == '\0' || *nick == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); if ((channel = muc_find(server, channame)) == NULL) cmd_param_error(CMDERR_NOT_JOINED); muc_nick(channel, nick); cmd_params_free(free_arg); } /* SYNTAX: TOPIC [-delete] [] [] */ static void cmd_topic(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { GHashTable *optlist; LmMessage *lmsg; char *channame, *topic, *recoded; void *free_arg; gboolean delete; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_OPTIONS | PARAM_FLAG_GETREST, item, "topic", &optlist, &channame, &topic)) return; if (muc_find(server, channame) == NULL) cmd_param_error(CMDERR_NOT_JOINED); g_strstrip(topic); delete = g_hash_table_lookup(optlist, "delete") != NULL; if (*topic != '\0' || delete) { recoded = xmpp_recode_out(channame); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_MESSAGE, LM_MESSAGE_SUB_TYPE_GROUPCHAT); g_free(recoded); if (delete) lm_message_node_add_child(lmsg->node, "subject", NULL); else { recoded = xmpp_recode_out(topic); lm_message_node_add_child(lmsg->node, "subject", recoded); g_free(recoded); } signal_emit("xmpp send message", 2, server, lmsg); lm_message_unref(lmsg); } cmd_params_free(free_arg); } void muc_commands_init(void) { command_bind_xmpp("invite", NULL, (SIGNAL_FUNC)cmd_invite); command_set_options("invite", "yes"); command_bind_xmpp("part", NULL, (SIGNAL_FUNC)cmd_part); command_bind_xmpp("nick", NULL, (SIGNAL_FUNC)cmd_nick); command_bind_xmpp("topic", NULL, (SIGNAL_FUNC)cmd_topic); } void muc_commands_deinit(void) { command_unbind("invite", (SIGNAL_FUNC)cmd_invite); command_unbind("part", (SIGNAL_FUNC)cmd_part); command_unbind("nick", (SIGNAL_FUNC)cmd_nick); command_unbind("topic", (SIGNAL_FUNC)cmd_topic); } src/core/xep/datetime.h0000644000175000017500000000016212261362415013141 0ustar fsfs#ifndef __DATETIME_H #define __DATETIME_H __BEGIN_DECLS time_t xep82_datetime(const char *); __END_DECLS #endif src/core/xep/muc-events.h0000644000175000017500000000021312261362415013430 0ustar fsfs#ifndef __MUC_EVENTS_H #define __MUC_EVENTS_H __BEGIN_DECLS void muc_events_init(void); void muc_events_deinit(void); __END_DECLS #endif src/core/xep/muc-events.c0000644000175000017500000003730612261362415013440 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0045: Multi-User Chat */ #include #include #include "module.h" #include "commands.h" #include "misc.h" #include "settings.h" #include "signals.h" #include "rosters-tools.h" #include "tools.h" #include "disco.h" #include "muc.h" #include "muc-nicklist.h" #define MAX_LONG_STRLEN ((sizeof(long) * CHAR_BIT + 2) / 3 + 1) void send_join(MUC_REC *); static void topic(MUC_REC *channel, const char *topic, const char *nickname) { if (channel->topic != NULL && topic != NULL && strcmp(channel->topic, topic) == 0) return; g_free(channel->topic); channel->topic = (topic != NULL && *topic != '\0') ? g_strdup(topic) : NULL; g_free(channel->topic_by); channel->topic_by = g_strdup(nickname); signal_emit("channel topic changed", 1, channel); if (channel->joined && nickname != NULL && *nickname != '\0') signal_emit("message topic", 5, channel->server, channel->name, (channel->topic != NULL) ? channel->topic : "", channel->topic_by, ""); else { char *data = g_strconcat(" ", channel->name, " :", (channel->topic != NULL) ? channel->topic : "", (void *)NULL); signal_emit("event 332", 2, channel->server, data); g_free(data); } } static void nick_changed(MUC_REC *channel, const char *oldnick, const char *newnick) { XMPP_NICK_REC *nick; if ((nick = xmpp_nicklist_find(channel, oldnick)) == NULL) return; xmpp_nicklist_rename(channel, nick, oldnick, newnick); if (channel->ownnick == NICK(nick)) signal_emit("message xmpp muc own_nick", 3, channel, nick, oldnick); else signal_emit("message xmpp muc nick", 3, channel, nick, oldnick); } static void own_join(MUC_REC *channel, const char *nickname, const char *full_jid, const char *affiliation, const char *role, gboolean forced) { XMPP_NICK_REC *nick; if (channel->joined) return; if ((nick = xmpp_nicklist_find(channel, nickname)) != NULL) return; nick = xmpp_nicklist_insert(channel, nickname, full_jid); nicklist_set_own(CHANNEL(channel), NICK(nick)); channel->chanop = channel->ownnick->op; xmpp_nicklist_set_modes(nick, xmpp_nicklist_get_affiliation(affiliation), xmpp_nicklist_get_role(role)); channel->names_got = TRUE; channel->joined = TRUE; signal_emit("message join", 4, channel->server, channel->name, nick->nick, nick->host); signal_emit("message xmpp muc mode", 4, channel, nick->nick, nick->affiliation, nick->role); signal_emit("channel joined", 1, channel); signal_emit("channel sync", 1, channel); channel_send_autocommands(CHANNEL(channel)); if (forced) nick_changed(channel, channel->nick, nick->nick); if (*channel->mode == '\0') disco_request(channel->server, channel->name); } static void nick_join(MUC_REC *channel, const char *nickname, const char *full_jid, const char *affiliation, const char *role) { XMPP_NICK_REC *nick; nick = xmpp_nicklist_insert(channel, nickname, full_jid); xmpp_nicklist_set_modes(nick, xmpp_nicklist_get_affiliation(affiliation), xmpp_nicklist_get_role(role)); if (channel->names_got) { signal_emit("message join", 4, channel->server, channel->name, nick->nick, nick->host); signal_emit("message xmpp muc mode", 4, channel, nick->nick, nick->affiliation, nick->role); } } static void nick_mode(MUC_REC *channel, XMPP_NICK_REC *nick, const char *affiliation_str, const char *role_str) { int affiliation, role; affiliation = xmpp_nicklist_get_affiliation(affiliation_str); role = xmpp_nicklist_get_role(role_str); if (xmpp_nicklist_modes_changed(nick, affiliation, role)) { xmpp_nicklist_set_modes(nick, affiliation, role); signal_emit("message xmpp muc mode", 4, channel, nick->nick, affiliation, role); } } static void own_event(MUC_REC *channel, const char *nickname, const char *full_jid, const char *affiliation, const char *role, gboolean forced) { XMPP_NICK_REC *nick; if ((nick = xmpp_nicklist_find(channel, nickname)) == NULL) own_join(channel, nickname, full_jid, affiliation, role, forced); else nick_mode(channel, nick, affiliation, role); } static void nick_event(MUC_REC *channel, const char *nickname, const char *full_jid, const char *affiliation, const char *role) { XMPP_NICK_REC *nick; if ((nick = xmpp_nicklist_find(channel, nickname)) == NULL) nick_join(channel, nickname, full_jid, affiliation, role); else nick_mode(channel, nick, affiliation, role); } static void nick_part(MUC_REC *channel, const char *nickname, const char *reason) { XMPP_NICK_REC *nick; if ((nick = xmpp_nicklist_find(channel, nickname)) == NULL) return; signal_emit("message part", 5, channel->server, channel->name, nick->nick, nick->host, reason); if (channel->ownnick == NICK(nick)) { channel->left = TRUE; channel_destroy(CHANNEL(channel)); } else nicklist_remove(CHANNEL(channel), NICK(nick)); } static void nick_presence(MUC_REC *channel, const char *nickname, const char *show_str, const char *status) { XMPP_NICK_REC *nick; int show; if ((nick = xmpp_nicklist_find(channel, nickname)) == NULL) return; show = xmpp_get_show(show_str); if (xmpp_presence_changed(show, nick->show, status, nick->status, 0, 0)) { xmpp_nicklist_set_presence(nick, show, status); if (channel->joined && channel->ownnick != NICK(nick)) { /* TODO eventually show event */ } } } static void nick_kicked(MUC_REC *channel, const char *nickname, const char *actor, const char *reason) { XMPP_NICK_REC *nick; if ((nick = xmpp_nicklist_find(channel, nickname)) == NULL) return; signal_emit("message kick", 6, channel->server, channel->name, nick->nick, (actor != NULL) ? actor : channel->name, nick->host, reason); if (channel->ownnick == NICK(nick)) { channel->kicked = TRUE; channel_destroy(CHANNEL(channel)); } else nicklist_remove(CHANNEL(channel), NICK(nick)); } static void error_message(MUC_REC *channel, const char *code) { int error; error = code != NULL ? atoi(code) : MUC_ERROR_UNKNOWN; switch (error) { case MUC_ERROR_PASSWORD_INVALID_OR_MISSING: signal_emit("xmpp muc error", 2, channel, "not allowed"); break; } } static void error_join(MUC_REC *channel, const char *code, const char *nick) { char *altnick; int error; if (nick != NULL && strcmp(nick, channel->nick) != 0) return; error = code != NULL ? atoi(code) : MUC_ERROR_UNKNOWN; signal_emit("xmpp muc joinerror", 2, channel, GINT_TO_POINTER(error)); switch(error) { case MUC_ERROR_USE_RESERVED_ROOM_NICK: case MUC_ERROR_NICK_IN_USE: /* rejoin with alternate nick */ altnick = (char *)settings_get_str("alternate_nick"); if (altnick != NULL && *altnick != '\0' && strcmp(channel->nick, altnick) != 0) { g_free(channel->nick); channel->nick = g_strdup(altnick); } else { altnick = g_strdup_printf("%s_", channel->nick); g_free(channel->nick); channel->nick = altnick; } send_join(channel); return; /* don't destroy the channel */ } channel_destroy(CHANNEL(channel)); } static void error_presence(MUC_REC *channel, const char *code, const char *nick) { int error; error = code != NULL ? atoi(code) : MUC_ERROR_UNKNOWN; switch (error) { case MUC_ERROR_NICK_IN_USE: signal_emit("message xmpp muc nick in use", 2, channel, nick); break; } } static void available(MUC_REC *channel, const char *from, LmMessage *lmsg) { LmMessageNode *node; const char *item_affiliation, *item_role, *nick; char *item_jid, *item_nick, *status; gboolean own, forced, created; item_affiliation = item_role = status = NULL; item_jid = item_nick = NULL; /* */ if ((node = lm_find_node(lmsg->node, "x", XMLNS, XMLNS_MUC_USER)) == NULL) return; /* */ own = lm_find_node(node, "status", "code", "110") != NULL; /* */ forced = lm_find_node(node, "status", "code", "210") != NULL; /* */ created = lm_find_node(node, "status", "code", "201") != NULL; if (created) { char str[MAX_LONG_STRLEN], *data; g_snprintf(str, sizeof(str), "%ld", (long)time(NULL)); data = g_strconcat("_ ", channel->name, " ", str, (void *)NULL); /* muc created */ signal_emit("event 329", 2, channel->server, data); g_free(data); } if ((node = lm_message_node_get_child(node, "item")) == NULL) return; /* */ item_affiliation = lm_message_node_get_attribute(node, "affiliation"); item_role = lm_message_node_get_attribute(node, "role"); item_jid = xmpp_recode_in( lm_message_node_get_attribute(node, "jid")); item_nick = xmpp_recode_in( lm_message_node_get_attribute(node, "nick")); nick = item_nick != NULL ? item_nick : from; if (nick == NULL) goto err; if (own || strcmp(nick, channel->nick) == 0) own_event(channel, nick, item_jid, item_affiliation, item_role, forced); else nick_event(channel, nick, item_jid, item_affiliation, item_role); /* text */ node = lm_message_node_get_child(lmsg->node, "status"); if (node != NULL) status = xmpp_recode_in(node->value); /* show */ node = lm_message_node_get_child(lmsg->node, "show"); nick_presence(channel, nick, node != NULL ? node->value : NULL, status); g_free(status); err: g_free(item_jid); g_free(item_nick); } static void unavailable(MUC_REC *channel, const char *nick, LmMessage *lmsg) { LmMessageNode *node, *child; const char *status_code; char *reason, *actor, *item_nick, *status; status_code = NULL; reason = actor = item_nick = status = NULL; /* */ node = lm_find_node(lmsg->node, "x", XMLNS, XMLNS_MUC_USER); if (node != NULL) { /* */ child = lm_message_node_get_child(node, "status"); if (child != NULL) status_code = lm_message_node_get_attribute(child, "code"); /* */ node = lm_message_node_get_child(node, "item"); if (node != NULL) { item_nick = xmpp_recode_in( lm_message_node_get_attribute(node, "nick")); /* reason */ child = lm_message_node_get_child(node, "reason"); if (child != NULL) reason = xmpp_recode_in(child->value); /* */ child = lm_message_node_get_child(node, "actor"); if (child != NULL) actor = xmpp_recode_in( lm_message_node_get_attribute(child, "jid")); } } if (status_code != NULL) { switch (atoi(status_code)) { case 303: /* */ nick_changed(channel, nick, item_nick); break; case 307: /* kick: */ nick_kicked(channel, nick, actor, reason); break; case 301: /* ban: */ nick_kicked(channel, nick, actor, reason); break; } } else { /* text */ node = lm_message_node_get_child(lmsg->node, "status"); if (node != NULL) status = xmpp_recode_in(node->value); nick_part(channel, nick, status); g_free(status); } g_free(item_nick); g_free(reason); g_free(actor); } static void invite(XMPP_SERVER_REC *server, const char *channame, LmMessageNode *node, LmMessageNode *invite_node) { LmMessageNode *pass; CHANNEL_SETUP_REC *setup; const char *from; char *inviter, *password, *joindata; if ((from = lm_message_node_get_attribute(invite_node, "from")) == NULL) return; inviter = xmpp_recode_in(from); pass = lm_message_node_get_child(node, "password"); password = pass != NULL ? xmpp_recode_in(pass->value) : NULL; signal_emit("xmpp invite", 4, server, inviter, channame, password); /* check if we're supposed to autojoin this muc */ setup = channel_setup_find(channame, server->connrec->chatnet); if (setup != NULL && setup->autojoin && settings_get_bool("join_auto_chans_on_invite")) { joindata = password == NULL ? g_strconcat("\"", channame, "\"", (void *)NULL) : g_strconcat("\"", channame, "\" ", password, (void *)NULL); muc_join(server, joindata, TRUE); g_free(joindata); } g_free(inviter); g_free(password); g_free(server->last_invite); server->last_invite = g_strdup(channame); } static void sig_recv_message(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { MUC_REC *channel; LmMessageNode *node, *child; char *nick, *str; gboolean action, own; if ((channel = get_muc(server, from)) == NULL) { /* Not a joined channel, search the MUC namespace */ /* */ node = lm_find_node(lmsg->node, "x", XMLNS, XMLNS_MUC_USER); if (node == NULL) return; switch (type) { case LM_MESSAGE_SUB_TYPE_NOT_SET: case LM_MESSAGE_SUB_TYPE_NORMAL: child = lm_message_node_get_child(node, "invite"); if (child != NULL) invite(server, from, node, child); break; } return; } nick = muc_extract_nick(from); switch (type) { case LM_MESSAGE_SUB_TYPE_ERROR: node = lm_message_node_get_child(lmsg->node, "error"); if (node != NULL) { /* TODO: extract error type and name -> XMLNS_STANZAS */ error_message(channel, lm_message_node_get_attribute(node, "code")); } break; case LM_MESSAGE_SUB_TYPE_GROUPCHAT: node = lm_message_node_get_child(lmsg->node, "subject"); if (node != NULL) { str = xmpp_recode_in(node->value); topic(channel, str, nick); g_free(str); } node = lm_message_node_get_child(lmsg->node, "body"); if (node != NULL && node->value != NULL && nick != NULL) { str = xmpp_recode_in(node->value); own = strcmp(nick, channel->nick) == 0; action = g_ascii_strncasecmp(str, "/me ", 4) == 0; if (action && own) signal_emit("message xmpp own_action", 4, server, str+4, channel->name, GINT_TO_POINTER(SEND_TARGET_CHANNEL)); else if (action) signal_emit("message xmpp action", 5, server, str+4, nick, channel->name, GINT_TO_POINTER(SEND_TARGET_CHANNEL)); else if (own) signal_emit("message xmpp own_public", 3, server, str, channel->name); else signal_emit("message public", 5, server, str, nick, "", channel->name); g_free(str); } break; } g_free(nick); } static void sig_recv_presence(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { MUC_REC *channel; LmMessageNode *node; const char *code; char *nick; if ((channel = get_muc(server, from)) == NULL) return; nick = muc_extract_nick(from); switch (type) { case LM_MESSAGE_SUB_TYPE_ERROR: node = lm_message_node_get_child(lmsg->node, "error"); if (node == NULL) goto out; /* TODO: extract error type and name -> XMLNS_STANZAS */ code = lm_message_node_get_attribute(node, "code"); if (!channel->joined) error_join(channel, code, nick); else error_presence(channel, code, nick); break; case LM_MESSAGE_SUB_TYPE_AVAILABLE: available(channel, nick, lmsg); break; case LM_MESSAGE_SUB_TYPE_UNAVAILABLE: unavailable(channel, nick, lmsg); break; } out: g_free(nick); } void muc_events_init(void) { signal_add("xmpp recv message", sig_recv_message); signal_add("xmpp recv presence", sig_recv_presence); } void muc_events_deinit(void) { signal_remove("xmpp recv message", sig_recv_message); signal_remove("xmpp recv presence", sig_recv_presence); } src/core/xep/registration.c0000644000175000017500000002275012261362415014061 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0077: In-Band Registration */ #include #include #include "module.h" #include "settings.h" #include "signals.h" #include "tools.h" #include "xmpp-servers.h" #include "xmpp-commands.h" #include "loudmouth-tools.h" #include "disco.h" #include "registration.h" #define XMLNS_REGISTRATION "http://jabber.org/features/iq-register" #define XMLNS_REGISTER "jabber:iq:register" gboolean set_ssl(LmConnection *, GError **, gpointer); gboolean set_proxy(LmConnection *, GError **); struct register_data { char *username; char *domain; char *password; char *address; int port; gboolean use_ssl; char *id; LmConnection *lmconn; LmMessageHandler *handler; }; GSList *register_data; static void rd_cleanup(struct register_data *rd) { register_data = g_slist_remove(register_data, rd); g_free(rd->username); g_free(rd->domain); g_free(rd->password); g_free(rd->address); g_free(rd->id); if (rd->handler != NULL) { if (lm_message_handler_is_valid(rd->handler)) lm_message_handler_invalidate(rd->handler); lm_message_handler_unref(rd->handler); } if (lm_connection_get_state(rd->lmconn) != LM_CONNECTION_STATE_CLOSED) lm_connection_close(rd->lmconn, NULL); lm_connection_unref(rd->lmconn); g_free(rd); } static LmHandlerResult handle_register(LmMessageHandler *handler, LmConnection *connection, LmMessage *lmsg, gpointer user_data) { LmMessageNode *node; struct register_data *rd; const char *id; char *cmd; int error; rd = user_data; id = lm_message_node_get_attribute(lmsg->node, "id"); if (id == NULL || (id != NULL && strcmp(id, rd->id) != 0)) return LM_HANDLER_RESULT_REMOVE_MESSAGE; if ((node = lm_message_node_get_child(lmsg->node, "error")) != NULL) { error = atoi(lm_message_node_get_attribute(node, "code")); signal_emit("xmpp registration failed", 3, rd->username, rd->domain, GINT_TO_POINTER(error)); } else { signal_emit("xmpp registration succeed", 2, rd->username, rd->domain); cmd = g_strdup_printf( "%sXMPPCONNECT %s-host %s -port %d %s@%s %s", settings_get_str("cmdchars"), rd->use_ssl ? "-ssl " : "", rd->address, rd->port, rd->username, rd->domain, rd->password); signal_emit("send command", 3, cmd, NULL, NULL); g_free(cmd); } rd_cleanup(rd); return LM_HANDLER_RESULT_REMOVE_MESSAGE; } static void send_register(struct register_data *rd) { LmMessage *lmsg; LmMessageNode *node; char *recoded; lmsg = lm_message_new_with_sub_type(rd->domain, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_REGISTER); recoded = xmpp_recode_out(rd->username); lm_message_node_add_child(node, "username", recoded); g_free(recoded); recoded = xmpp_recode_out(rd->password); lm_message_node_add_child(node, "password", recoded); g_free(recoded); rd->id = g_strdup(lm_message_node_get_attribute(lmsg->node, "id")); if (!lm_connection_send_with_reply(rd->lmconn, lmsg, rd->handler, NULL)) { signal_emit("xmpp registration failed", 3, rd->username, rd->domain, REGISTRATION_ERROR_INFO); rd_cleanup(rd); } lm_message_unref(lmsg); } static void register_lm_close_cb(LmConnection *connection, LmDisconnectReason reason, gpointer user_data) { struct register_data *rd; if (reason == LM_DISCONNECT_REASON_OK) return; rd = user_data; signal_emit("xmpp registration failed", 3, rd->username, rd->domain, REGISTRATION_ERROR_UNKNOWN); rd_cleanup(rd); } static void register_lm_open_cb(LmConnection *connection, gboolean success, gpointer user_data) { struct register_data *rd; rd = user_data; if (!success) goto err; rd->handler = lm_message_handler_new(handle_register, rd, NULL); send_register(rd); return; err: signal_emit("xmpp registration failed", 3, rd->username, rd->domain, REGISTRATION_ERROR_CONNECTION); rd_cleanup(rd); } static void start_registration(struct register_data *rd) { LmConnection *lmconn; GError *error = NULL; lmconn = lm_connection_new(NULL); if (rd->use_ssl && !set_ssl(lmconn, &error, NULL)) goto err; if (settings_get_bool("xmpp_use_proxy") && !set_proxy(lmconn, &error)) goto err; if (rd->port <= 0) rd->port = rd->use_ssl ? LM_CONNECTION_DEFAULT_PORT_SSL : LM_CONNECTION_DEFAULT_PORT; lm_connection_set_server(lmconn, rd->address); lm_connection_set_port(lmconn, rd->port); lm_connection_set_jid(lmconn, NULL); rd->id = NULL; rd->lmconn = lmconn; rd->handler = NULL; register_data = g_slist_prepend(register_data, rd); lm_connection_set_disconnect_function(lmconn, register_lm_close_cb, rd, NULL); if (!lm_connection_open(lmconn, register_lm_open_cb, rd, NULL, &error)) { rd_cleanup(rd); signal_emit("xmpp register error", 3, rd->username, rd->domain, error != NULL ? error->message : NULL); if (error != NULL) g_error_free(error); } return; err: signal_emit("xmpp register error", 3, rd->username, rd->domain, error != NULL ? error->message : NULL); if (error != NULL) g_error_free(error); lm_connection_unref(lmconn); } /* SYNTAX: XMPPREGISTER [-ssl] [-host ] [-port ] * */ static void cmd_xmppregister(const char *data, SERVER_REC *server, WI_ITEM_REC *item) { GHashTable *optlist; char *str, *jid, *password, *address; void *free_arg; struct register_data *rd; if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS, "xmppconnect", &optlist, &jid, &password)) return; if (*jid == '\0' || *password == '\0' || !xmpp_have_domain(jid)) cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); rd = g_new0(struct register_data, 1); rd->username = xmpp_extract_user(jid); rd->domain = xmpp_extract_domain(jid); rd->password = g_strdup(password); address = g_hash_table_lookup(optlist, "host"); if (address == NULL || *address == '\0') address = rd->domain; rd->address = g_strdup(address); rd->port = (str = g_hash_table_lookup(optlist, "port")) ? atoi(str) : 0; rd->use_ssl = g_hash_table_lookup(optlist, "ssl") != NULL; signal_emit("xmpp registration started", 2, rd->username, rd->domain); start_registration(rd); cmd_params_free(free_arg); } /* SYNTAX: XMPPUNREGISTER -yes */ static void cmd_xmppunregister(const char *data, SERVER_REC *server, WI_ITEM_REC *item) { GHashTable *optlist; LmMessage *lmsg; LmMessageNode *node; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 0 | PARAM_FLAG_OPTIONS, "xmppunregister", &optlist)) return; if (g_hash_table_lookup(optlist, "yes") == NULL) cmd_param_error(CMDERR_NOT_GOOD_IDEA); lmsg = lm_message_new_with_sub_type(NULL, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_REGISTER); lm_message_node_add_child(node, "remove", NULL); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); cmd_params_free(free_arg); } /* SYNTAX: XMPPPASSWD -yes */ static void cmd_xmpppasswd(const char *data, SERVER_REC *server, WI_ITEM_REC *item) { GHashTable *optlist; char *old_password, *new_password, *recoded; LmMessage *lmsg; LmMessageNode *node; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS, "xmpppasswd", &optlist, &old_password, &new_password)) return; if (g_hash_table_lookup(optlist, "yes") == NULL) cmd_param_error(CMDERR_NOT_GOOD_IDEA); if (strcmp(old_password, server->connrec->password) != 0) cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); lmsg = lm_message_new_with_sub_type(XMPP_SERVER(server)->domain, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_REGISTER); recoded = xmpp_recode_out(XMPP_SERVER(server)->user); lm_message_node_add_child(node, "username", recoded); g_free(recoded); recoded = xmpp_recode_out(new_password); lm_message_node_add_child(node, "password", recoded); g_free(recoded); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); cmd_params_free(free_arg); } void registration_init(void) { register_data = NULL; command_bind("xmppregister", NULL, (SIGNAL_FUNC)cmd_xmppregister); command_bind("xmppunregister", NULL, (SIGNAL_FUNC)cmd_xmppunregister); command_set_options("xmppunregister", "yes"); command_bind("xmpppasswd", NULL, (SIGNAL_FUNC)cmd_xmpppasswd); command_set_options("xmpppasswd", "yes"); disco_add_feature(XMLNS_REGISTRATION); } void registration_deinit(void) { GSList *tmp, *next; command_unbind("xmppregister", (SIGNAL_FUNC)cmd_xmppregister); command_unbind("xmppunregister", (SIGNAL_FUNC)cmd_xmppunregister); command_unbind("xmpppasswd", (SIGNAL_FUNC)cmd_xmpppasswd); for (tmp = register_data; tmp != NULL; tmp = next) { next = tmp->next; rd_cleanup((struct register_data *)tmp->data); } } src/core/xep/muc.c0000644000175000017500000002543012261362415012131 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0045: Multi-User Chat */ #include #include "module.h" #include "commands.h" #include "settings.h" #include "signals.h" #include "rosters-tools.h" #include "tools.h" #include "disco.h" #include "muc.h" #include "muc-commands.h" #include "muc-events.h" #include "muc-nicklist.h" #include "muc-reconnect.h" static char * get_join_data(MUC_REC *channel) { if (channel->key != NULL) return g_strdup_printf("\"%s/%s\" \"%s\"", channel->name, channel->nick, channel->key); else return g_strdup_printf("\"%s/%s\"", channel->name, channel->nick); } CHANNEL_REC * muc_create(XMPP_SERVER_REC *server, const char *name, const char *visible_name, int automatic, const char *nick) { MUC_REC *rec; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); g_return_val_if_fail(name != NULL, NULL); rec = g_new0(MUC_REC, 1); rec->chat_type = XMPP_PROTOCOL; rec->nick = g_strdup((nick != NULL) ? nick : (*settings_get_str("nick") != '\0') ? settings_get_str("nick") : server->user); channel_init((CHANNEL_REC *)rec, SERVER(server), name, visible_name, automatic); rec->get_join_data = (char *(*)(CHANNEL_REC *))get_join_data; return (CHANNEL_REC *)rec; } void muc_nick(MUC_REC *channel, const char *nick) { LmMessage *lmsg; LmMessageNode *node; char *recoded, *str; g_return_if_fail(IS_MUC(channel)); if (!channel->server->connected) return; str = g_strconcat(channel->name, "/", nick, (void *)NULL); recoded = xmpp_recode_out(str); g_free(str); lmsg = lm_message_new(recoded, LM_MESSAGE_TYPE_PRESENCE); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "x", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_MUC); if (!channel->joined) { if (channel->key != NULL) { recoded = xmpp_recode_out(channel->key); lm_message_node_add_child(node, "password", recoded); g_free(recoded); } node = lm_message_node_add_child(node, "history", NULL); str = g_strdup_printf("%d", settings_get_int("xmpp_history_maxstanzas")); lm_message_node_set_attribute(node, "maxstanzas", str); g_free(str); if (channel->server->show != XMPP_PRESENCE_AVAILABLE) { recoded = xmpp_recode_out( xmpp_presence_show[channel->server->show]); lm_message_node_add_child(lmsg->node, "show", recoded); g_free(recoded); } if (channel->server->away_reason != NULL) { recoded = xmpp_recode_out( channel->server->away_reason); lm_message_node_add_child(lmsg->node, "status", recoded); g_free(recoded); } } signal_emit("xmpp send presence", 2, channel->server, lmsg); lm_message_unref(lmsg); } void send_join(MUC_REC *channel) { g_return_if_fail(IS_MUC(channel)); if (!channel->server->connected) return; muc_nick(channel, channel->nick); } void muc_join(XMPP_SERVER_REC *server, const char *data, gboolean automatic) { MUC_REC *channel; char *chanline, *channame, *nick, *key; void *free_arg; g_return_if_fail(IS_XMPP_SERVER(server)); g_return_if_fail(data != NULL); if (!server->connected) return; if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &chanline, &key)) return; nick = muc_extract_nick(chanline); channame = muc_extract_channel(chanline); if (muc_find(server, channame) == NULL) { channel = (MUC_REC *)muc_create(server, channame, NULL, automatic, nick); channel->key = (key == NULL || *key == '\0') ? NULL : g_strdup(key); send_join(channel); } g_free(nick); g_free(channame); cmd_params_free(free_arg); } static void send_part(MUC_REC *channel, const char *reason) { LmMessage *lmsg; LmMessageNode *node; char *channame, *recoded; if (!channel->server->connected) return; channame = g_strconcat(channel->name, "/", channel->nick, (void *)NULL); recoded = xmpp_recode_out(channame); g_free(channame); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_UNAVAILABLE); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "x", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_MUC); if (reason != NULL) { recoded = xmpp_recode_out(reason); lm_message_node_add_child(lmsg->node, "status", recoded); g_free(recoded); } signal_emit("xmpp send presence", 2, channel->server, lmsg); lm_message_unref(lmsg); } void muc_part(MUC_REC *channel, const char *reason) { g_return_if_fail(IS_MUC(channel)); send_part(channel, reason); channel->left = TRUE; if (channel->ownnick != NULL) signal_emit("message part", 5, channel->server, channel->name, channel->ownnick->nick, channel->ownnick->host, reason); channel_destroy(CHANNEL(channel)); } static void sig_features(XMPP_SERVER_REC *server, const char *name, GSList *list) { MUC_REC *channel; GString *modes; if ((channel = muc_find(server, name)) == NULL) return; modes = g_string_new(NULL); if (disco_have_feature(list, "muc_hidden")) g_string_append(modes, "h"); if (disco_have_feature(list, "muc_membersonly")) g_string_append(modes, "m"); if (disco_have_feature(list, "muc_moderated")) g_string_append(modes, "M"); if (disco_have_feature(list, "muc_nonanonymous")) g_string_append(modes, "a"); if (disco_have_feature(list, "muc_open")) g_string_append(modes, "o"); if (disco_have_feature(list, "muc_passwordprotected")) g_string_append(modes, "k"); if (disco_have_feature(list, "muc_persistent")) g_string_append(modes, "p"); if (disco_have_feature(list, "muc_public")) g_string_append(modes, "u"); if (disco_have_feature(list, "muc_semianonymous")) g_string_append(modes, "b"); if (disco_have_feature(list, "muc_temporary")) g_string_append(modes, "t"); if (disco_have_feature(list, "muc_unmoderated")) g_string_append(modes, "n"); if (disco_have_feature(list, "muc_unsecured")) g_string_append(modes, "d"); if (disco_have_feature(list, "muc_passwordprotected") && channel->key != NULL) g_string_append_printf(modes, " %s", channel->key); if (strcmp(modes->str, channel->mode) != 0) { g_free(channel->mode); channel->mode = modes->str; signal_emit("channel mode changed", 2, channel, channel->name); } g_string_free(modes, FALSE); } static void sig_channel_created(MUC_REC *channel) { if (!IS_MUC(channel)) return; if (channel->nicks != NULL) g_hash_table_destroy(channel->nicks); channel->nicks = g_hash_table_new((GHashFunc)g_str_hash, (GCompareFunc)g_str_equal); } static void sig_channel_destroyed(MUC_REC *channel) { if (!IS_MUC(channel)) return; if (!channel->server->disconnected && !channel->left) muc_part(channel, settings_get_str("part_message")); g_free(channel->nick); } static CHANNEL_REC * channel_find_func(SERVER_REC *server, const char *channel_name) { GSList *tmp; CHANNEL_REC *channel; for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { channel = tmp->data; if (channel->chat_type != server->chat_type) continue; if (g_ascii_strcasecmp(channel_name, channel->name) == 0) return channel; } return NULL; } static void channels_join_func(SERVER_REC *server, const char *data, int automatic) { /* ignore automatic joins from irssi */ if (automatic) return; muc_join(XMPP_SERVER(server), data, FALSE); } static int ischannel_func(SERVER_REC *server, const char *data) { char *str; gboolean r; str = muc_extract_channel(data); r = muc_find(server, data) != NULL ? TRUE : FALSE; g_free(str); return r; } MUC_REC * get_muc(XMPP_SERVER_REC *server, const char *data) { MUC_REC *channel; char *str; str = muc_extract_channel(data); channel = muc_find(server, str); g_free(str); return channel; } static void sig_connected(SERVER_REC *server) { GSList *tmp; CHANNEL_SETUP_REC *channel_setup; if (!IS_XMPP_SERVER(server)) return; server->channel_find_func = channel_find_func; server->channels_join = channels_join_func; server->ischannel = ischannel_func; /* autojoin channels */ if (!server->connrec->no_autojoin_channels) { for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) { channel_setup = tmp->data; if (IS_MUC_SETUP(channel_setup) && channel_setup->autojoin && strcmp(channel_setup->chatnet, server->connrec->chatnet) == 0) muc_join(XMPP_SERVER(server), channel_setup->name, TRUE); } } } static void send_muc_presence(MUC_REC *channel, const int show, const char *status) { LmMessage *lmsg; char *channame, *str; channame = g_strconcat(channel->name, "/", channel->nick, (void *)NULL); str = xmpp_recode_out(channame); g_free(channame); lmsg = lm_message_new(str, LM_MESSAGE_TYPE_PRESENCE); g_free(str); if (show != XMPP_PRESENCE_AVAILABLE) lm_message_node_add_child(lmsg->node, "show", xmpp_presence_show[show]); if (status != NULL) { str = xmpp_recode_out(status); lm_message_node_add_child(lmsg->node, "status", str); g_free(str); } signal_emit("xmpp send presence", 2, channel->server, lmsg); lm_message_unref(lmsg); } static void sig_set_presence(XMPP_SERVER_REC *server, const int show, const char *status, const int priority) { GSList *tmp; MUC_REC *channel; g_return_if_fail(IS_XMPP_SERVER(server)); if (!server->connected) return; for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { channel = MUC(tmp->data); send_muc_presence(channel, show, status); } } void muc_init(void) { CHAT_PROTOCOL_REC *chat; if ((chat = chat_protocol_find(XMPP_PROTOCOL_NAME)) != NULL) chat->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, const char *, int))muc_create; disco_add_feature(XMLNS_MUC); muc_commands_init(); muc_events_init(); muc_nicklist_init(); muc_reconnect_init(); signal_add("xmpp features", sig_features); signal_add("channel created", sig_channel_created); signal_add("channel destroyed", sig_channel_destroyed); signal_add("server connected", sig_connected); signal_add("xmpp set presence", sig_set_presence); settings_add_int("xmpp_lookandfeel", "xmpp_history_maxstanzas", 30); } void muc_deinit(void) { signal_remove("xmpp features", sig_features); signal_remove("channel created", sig_channel_created); signal_remove("channel destroyed",sig_channel_destroyed); signal_remove("server connected", sig_connected); signal_remove("xmpp set presence", sig_set_presence); muc_commands_deinit(); muc_events_deinit(); muc_nicklist_deinit(); muc_reconnect_deinit(); } src/core/xep/delay.c0000644000175000017500000000566212261362415012450 0ustar fsfs/* * Copyright (C) 2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0203: Delayed Delivery */ #include "module.h" #include "signals.h" #include "xmpp-servers.h" #include "tools.h" #include "datetime.h" #include "disco.h" #include "muc.h" #define XMLNS_DELAY "urn:xmpp:delay" #define XMLNS_OLD_DELAY "jabber:x:delay" static void sig_recv_message(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node; MUC_REC *channel; const char *stamp; char *nick, *str; time_t t; node = lm_find_node(lmsg->node, "delay", "xmlns", XMLNS_DELAY); if (node == NULL) { /* XEP-0091: Delayed Delivery (deprecated) */ node = lm_find_node(lmsg->node, "x", "xmlns", XMLNS_OLD_DELAY); if (node == NULL) return; } stamp = lm_message_node_get_attribute(node, "stamp"); if ((t = xep82_datetime(stamp)) == (time_t)-1) return; node = lm_message_node_get_child(lmsg->node, "body"); if (node == NULL || node->value == NULL || *node->value == '\0') return; if (type == LM_MESSAGE_SUB_TYPE_GROUPCHAT && (channel = get_muc(server, from)) != NULL && (nick = muc_extract_nick(from)) != NULL) { str = xmpp_recode_in(node->value); if (g_ascii_strncasecmp(str, "/me ", 4) == 0) signal_emit("message xmpp delay action", 6, server, str+4, nick, channel->name, &t, GINT_TO_POINTER(SEND_TARGET_CHANNEL)); else signal_emit("message xmpp delay", 6, server, str, nick, channel->name, &t, GINT_TO_POINTER(SEND_TARGET_CHANNEL)); g_free(str); g_free(nick); } else if ((type == LM_MESSAGE_SUB_TYPE_NOT_SET || type == LM_MESSAGE_SUB_TYPE_HEADLINE || type == LM_MESSAGE_SUB_TYPE_NORMAL || type == LM_MESSAGE_SUB_TYPE_CHAT)) { str = xmpp_recode_in(node->value); if (g_ascii_strncasecmp(str, "/me ", 4) == 0) signal_emit("message xmpp delay action", 6, server, str+4, from, from, &t, GINT_TO_POINTER(SEND_TARGET_NICK)); else signal_emit("message xmpp delay", 6, server, str+4, from, from, &t, GINT_TO_POINTER(SEND_TARGET_NICK)); g_free(str); } else return; signal_stop(); } void delay_init(void) { disco_add_feature(XMLNS_DELAY); signal_add_first("xmpp recv message", sig_recv_message); } void delay_deinit(void) { signal_remove("xmpp recv message", sig_recv_message); } src/core/xep/vcard.c0000644000175000017500000000724112261362415012444 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "queries.h" #include "signals.h" #include "xmpp-servers.h" #include "xmpp-commands.h" #include "tools.h" #include "disco.h" #define XMLNS_VCARD "vcard-temp" static void request_vcard(XMPP_SERVER_REC *server, const char *dest) { LmMessage *lmsg; LmMessageNode *node; char *recoded; recoded = xmpp_recode_out(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "vCard", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_VCARD); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } /* SYNTAX: VCARD [|] * SYNTAX: WHOIS [|] */ static void cmd_vcard(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item) { char *cmd_dest, *dest; void *free_arg; CMD_XMPP_SERVER(server); if (!cmd_get_params(data, &free_arg, 1, &cmd_dest)) return; dest = xmpp_get_dest(cmd_dest, server, item); request_vcard(server, dest); g_free(dest); cmd_params_free(free_arg); } static void vcard_handle(XMPP_SERVER_REC *server, const char *jid, LmMessageNode *node) { LmMessageNode *child, *subchild; GHashTable *ht; const char *adressing; char *value; ht = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); child = node->children; while (child != NULL) { /* ignore avatar */ if (g_ascii_strcasecmp(child->name, "PHOTO") == 0) goto next; if (child->value != NULL) { value = xmpp_recode_in(child->value); g_strstrip(value); g_hash_table_insert(ht, child->name, value); goto next; } /* find the adressing type indicator */ subchild = child->children; adressing = NULL; while (subchild != NULL && adressing == NULL) { if (subchild->value == NULL && ( g_ascii_strcasecmp(subchild->name , "HOME") == 0 || g_ascii_strcasecmp(subchild->name , "WORK") == 0)) adressing = subchild->name; subchild = subchild->next; } subchild = child->children; while (subchild != NULL) { if (subchild->value != NULL) { value = xmpp_recode_in(subchild->value); /* TODO sub... */ g_free(value); } subchild = subchild->next; } next: child = child->next; } signal_emit("xmpp vcard", 3, server, jid, ht); g_hash_table_destroy(ht); } static void sig_recv_iq(XMPP_SERVER_REC *server, LmMessage *lmsg, const int type, const char *id, const char *from, const char *to) { LmMessageNode *node; if (type != LM_MESSAGE_SUB_TYPE_RESULT) return; node = lm_find_node(lmsg->node, "vCard", XMLNS, XMLNS_VCARD); if (node != NULL) vcard_handle(server, from, node); } void vcard_init(void) { disco_add_feature(XMLNS_VCARD); command_bind_xmpp("vcard", NULL, (SIGNAL_FUNC)cmd_vcard); command_bind_xmpp("whois", NULL, (SIGNAL_FUNC)cmd_vcard); signal_add("xmpp recv iq", sig_recv_iq); } void vcard_deinit(void) { command_unbind("vcard", (SIGNAL_FUNC)cmd_vcard); command_unbind("whois", (SIGNAL_FUNC)cmd_vcard); signal_remove("xmpp recv iq", sig_recv_iq); } src/core/xep/chatstates.h0000644000175000017500000000021312261362415013505 0ustar fsfs#ifndef __CHATSTATES_H #define __CHATSTATES_H __BEGIN_DECLS void chatstates_init(void); void chatstates_deinit(void); __END_DECLS #endif src/core/xep/datetime.c0000644000175000017500000000445112261362415013141 0ustar fsfs/* * Copyright (C) 2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0082: XMPP Date and Time Profiles */ #ifdef __linux__ #define _XOPEN_SOURCE #endif #include #include #include #include #define FORMAT "%Y-%m-%dT%T" #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) static long parse_timezone(const char *tz) { const char *rfc822_timezones[][4] = { { "M", NULL }, /* UTC-12 */ { "L", NULL }, { "K", NULL }, { "I", NULL }, { "H", "PST", NULL }, /* UTC-8 */ { "G", "MST", "PDT", NULL }, /* UTC-7 */ { "F", "CST", "MDT", NULL }, /* UTC-6 */ { "E", "EST", "CDT", NULL }, /* UTC-5 */ { "D", "EDT", NULL }, /* UTC-4 */ { "C", NULL }, { "B", NULL }, { "A", NULL }, { "Z", "UT", "GMT", NULL }, /* UTC */ { "N", NULL }, { "O", NULL }, { "P", NULL }, { "Q", NULL }, { "R", NULL }, { "S", NULL }, { "T", NULL }, { "U", NULL }, { "V", NULL }, { "W", NULL }, { "X", NULL }, { "Y", NULL }, /* UTC+12 */ { NULL }, }; unsigned int i, j; if ((*tz == '+' || *tz == '-') && strlen(tz) == 5) { i = atoi(tz); return ((i/100)*60 + i%100) * 60; } for (i = 0; i < nitems(rfc822_timezones); ++i) for (j = 0; rfc822_timezones[i][j] != NULL; ++j) if (strcmp(rfc822_timezones[i][j], tz) == 0) return (i - 12) * 3600; return 0; } time_t xep82_datetime(const char *stamp) { struct tm tm; long offset; char *s; memset(&tm, 0, sizeof(struct tm)); if ((s = strptime(stamp, FORMAT, &tm)) == NULL) return (time_t)-1; /* ignore fractional second addendum */ if (*s++ == '.') while (isdigit(*s)) s++; tm.tm_isdst = -1; offset = *s != '\0' ? parse_timezone(s) : 0; return mktime(&tm) - offset; } src/core/xep/xep.c0000644000175000017500000000252412261362415012140 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "chatstates.h" #include "composing.h" #include "delay.h" #include "disco.h" #include "muc.h" #include "oob.h" #include "ping.h" #include "registration.h" #include "vcard.h" #include "version.h" void xep_init(void) { disco_init(); /* init sevice discovery first */ chatstates_init(); composing_init(); delay_init(); muc_init(); oob_init(); ping_init(); registration_init(); vcard_init(); version_init(); } void xep_deinit(void) { disco_deinit(); chatstates_deinit(); composing_deinit(); delay_deinit(); muc_deinit(); oob_deinit(); ping_deinit(); registration_deinit(); vcard_deinit(); version_deinit(); } src/core/xep/muc-reconnect.c0000644000175000017500000000637312261362415014114 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "module.h" #include "servers-reconnect.h" #include "signals.h" #include "xmpp-servers.h" #include "muc.h" static void sig_conn_copy(SERVER_CONNECT_REC **dest, XMPP_SERVER_CONNECT_REC *src) { GSList *tmp; XMPP_SERVER_CONNECT_REC *conn; g_return_if_fail(dest != NULL); if (!IS_XMPP_SERVER_CONNECT(src)) return; conn = (XMPP_SERVER_CONNECT_REC *)*dest; conn->channels_list = NULL; for (tmp = src->channels_list; tmp != NULL; tmp = tmp->next) { conn->channels_list = g_slist_append(conn->channels_list, g_strdup(tmp->data)); } } static void sig_conn_remove(RECONNECT_REC *rec) { XMPP_SERVER_CONNECT_REC *conn; if (!IS_XMPP_SERVER_CONNECT(rec->conn)) return; conn = XMPP_SERVER_CONNECT(rec->conn); g_slist_foreach(conn->channels_list, (GFunc)g_free, NULL); g_slist_free(conn->channels_list); } static void save_channels(XMPP_SERVER_REC *server, XMPP_SERVER_CONNECT_REC *conn) { GSList *tmp; MUC_REC *channel; char *joindata; if (conn->channels_list != NULL) { g_slist_foreach(conn->channels_list, (GFunc)g_free, NULL); g_slist_free(conn->channels_list); conn->channels_list = NULL; } for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { channel = tmp->data; joindata = channel->get_join_data(CHANNEL(channel)); conn->channels_list = g_slist_append(conn->channels_list, joindata); } } static void restore_channels(XMPP_SERVER_REC *server) { GSList *tmp; if (server->connrec->channels_list != NULL) return; for (tmp = server->connrec->channels_list; tmp != NULL; tmp = tmp->next) { muc_join(server, tmp->data, TRUE); g_free(tmp->data); } g_slist_free(server->connrec->channels_list); server->connrec->channels_list = NULL; } static void sig_save_status(XMPP_SERVER_CONNECT_REC *conn, XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER_CONNECT(conn) || !IS_XMPP_SERVER(server) || !server->connected) return; save_channels(server, conn); } static void sig_connected(XMPP_SERVER_REC *server) { if (!IS_XMPP_SERVER(server) || !server->connrec->reconnection) return; restore_channels(server); } void muc_reconnect_init(void) { signal_add_last("server connect copy", sig_conn_copy); signal_add("server reconnect remove", sig_conn_remove); signal_add("server reconnect save status", sig_save_status); signal_add_last("server connected", sig_connected); } void muc_reconnect_deinit(void) { signal_remove("server connect copy", sig_conn_copy); signal_remove("server reconnect remove", sig_conn_remove); signal_remove("server reconnect save status", sig_save_status); signal_remove("server connected", sig_connected); } src/core/xep/delay.h0000644000175000017500000000016712261362415012450 0ustar fsfs#ifndef __DELAY_H #define __DELAY_H __BEGIN_DECLS void delay_init(void); void delay_deinit(void); __END_DECLS #endif src/core/xep/version.c0000644000175000017500000001011512261362415013024 0ustar fsfs/* * Copyright (C) 2007,2008,2009 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * XEP-0092: Software Version */ #include #include #include "module.h" #include "queries.h" #include "settings.h" #include "signals.h" #include "xmpp-servers.h" #include "xmpp-commands.h" #include "disco.h" #include "tools.h" #define XMLNS_VERSION "jabber:iq:version" static void send_version(XMPP_SERVER_REC *server, const char *dest, const char *id) { LmMessage *lmsg; LmMessageNode *node; struct utsname u; char *recoded; recoded = xmpp_recode_out(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_RESULT); g_free(recoded); if (id != NULL) lm_message_node_set_attribute(lmsg->node, "id", id); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_VERSION); if (settings_get_bool("xmpp_send_version")) { lm_message_node_add_child(node, "name", IRSSI_XMPP_PACKAGE); lm_message_node_add_child(node, "version", IRSSI_XMPP_VERSION); if (uname(&u) == 0) lm_message_node_add_child(node, "os", u.sysname); } signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } static void request_version(XMPP_SERVER_REC *server, const char *dest) { LmMessage *lmsg; LmMessageNode *node; char *recoded; recoded = xmpp_recode_out(dest); lmsg = lm_message_new_with_sub_type(recoded, LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET); g_free(recoded); node = lm_message_node_add_child(lmsg->node, "query", NULL); lm_message_node_set_attribute(node, XMLNS, XMLNS_VERSION); signal_emit("xmpp send iq", 2, server, lmsg); lm_message_unref(lmsg); } /* SYNTAX: VER [[[/]]|[node,"query", XMLNS, XMLNS_VERSION)) != NULL) { name = version = os = NULL; for (child = node->children; child != NULL; child = child->next) { if (child->value == NULL) continue; if (name == NULL && strcmp(child->name, "name") == 0) g_strstrip(name = xmpp_recode_in(child->value)); else if (version == NULL && strcmp(child->name, "version") == 0) g_strstrip(version = xmpp_recode_in(child->value)); else if (os == NULL && strcmp(child->name, "os") == 0) g_strstrip(os = xmpp_recode_in(child->value)); } signal_emit("xmpp version", 5, server, from, name, version, os); g_free(name); g_free(version); g_free(os); } else if (type == LM_MESSAGE_SUB_TYPE_GET && (node = lm_find_node(lmsg->node,"query", XMLNS, XMLNS_VERSION)) != NULL) send_version(server, from, id); } void version_init(void) { disco_add_feature(XMLNS_VERSION); settings_add_bool("xmpp", "xmpp_send_version", TRUE); command_bind_xmpp("ver", NULL, (SIGNAL_FUNC)cmd_ver); signal_add("xmpp recv iq", sig_recv_iq); } void version_deinit(void) { command_unbind("ver", (SIGNAL_FUNC)cmd_ver); signal_remove("xmpp recv iq", sig_recv_iq); } src/core/module.h0000644000175000017500000000014112261357644012043 0ustar fsfs#define MODULE_NAME "xmpp/core" #include "irssi-config.h" #include "common.h" #include "xmpp.h" src/core/rosters-tools.c0000644000175000017500000001403512261362415013407 0ustar fsfs/* * Copyright (C) 2007 Colin DIDIER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include "module.h" #include "xmpp-servers.h" #include "rosters-tools.h" #include "tools.h" static int find_user_func(gconstpointer user, gconstpointer jid) { g_return_val_if_fail(user != NULL, -1); g_return_val_if_fail(jid != NULL, -1); return strcmp(((XMPP_ROSTER_USER_REC *)user)->jid, jid); } static int find_username_func(gconstpointer user_pointer, gconstpointer name) { XMPP_ROSTER_USER_REC *user; g_return_val_if_fail(user_pointer != NULL, -1); user = (XMPP_ROSTER_USER_REC *)user_pointer; if (user->name == NULL) return -1; return strcmp(user->name, name); } static int find_resource_func(gconstpointer resource, gconstpointer name) { char *res; g_return_val_if_fail(resource != NULL, -1); res = ((XMPP_ROSTER_RESOURCE_REC *)resource)->name; if(res == NULL && name == NULL) return 0; if (res == NULL || name == NULL) return -1; return strcmp(res, name); } XMPP_ROSTER_GROUP_REC * find_group_from_user(XMPP_SERVER_REC *server, XMPP_ROSTER_USER_REC *user) { GSList *gl, *gl_found; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); gl = server->roster; gl_found = NULL; while (gl_found != NULL && gl != NULL) { gl_found = g_slist_find(gl, user); gl = gl->next; } return (XMPP_ROSTER_GROUP_REC *)gl->data; } XMPP_ROSTER_USER_REC * rosters_find_user(GSList *groups, const char *jid, XMPP_ROSTER_GROUP_REC **group, XMPP_ROSTER_RESOURCE_REC **resource) { GSList *group_tmp, *gl, *ul; char *pos; if ((pos = xmpp_find_resource_sep(jid)) != NULL) *pos = '\0'; group_tmp = ul = NULL; for (gl = groups; ul == NULL && gl != NULL; gl = gl->next) { ul = g_slist_find_custom( ((XMPP_ROSTER_GROUP_REC *)gl->data)->users, jid, find_user_func); group_tmp = gl; } if (group != NULL) *group = ul != NULL ? (XMPP_ROSTER_GROUP_REC *)group_tmp->data : NULL; if (resource != NULL) *resource = ul != NULL && pos != NULL ? rosters_find_resource( ((XMPP_ROSTER_USER_REC *)ul->data)->resources, pos+1) : NULL; if (pos != NULL) *pos = '/'; return ul != NULL ? (XMPP_ROSTER_USER_REC *)ul->data : NULL; } XMPP_ROSTER_USER_REC * find_username(GSList *groups, const char *name, XMPP_ROSTER_GROUP_REC **group) { GSList *gl, *group_tmp, *ul; gl = groups; group_tmp = ul = NULL; while (ul == NULL && gl != NULL) { ul = g_slist_find_custom( ((XMPP_ROSTER_GROUP_REC *)gl->data)->users, name, find_username_func); group_tmp = gl; gl = g_slist_next(gl); } if (group != NULL && group_tmp != NULL) *group = group_tmp->data; return ul ? (XMPP_ROSTER_USER_REC *)ul->data : NULL; } XMPP_ROSTER_RESOURCE_REC * rosters_find_resource(GSList *resources, const char *res) { GSList *resource; if (resources == NULL) return NULL; resource = g_slist_find_custom(resources, res, find_resource_func); return resource != NULL ? (XMPP_ROSTER_RESOURCE_REC *)resource->data : NULL; } XMPP_ROSTER_RESOURCE_REC * rosters_find_own_resource(XMPP_SERVER_REC *server, const char *resource) { GSList *resource_list; g_return_val_if_fail(server != NULL, NULL); resource_list = g_slist_find_custom(server->my_resources, resource, find_resource_func); return resource_list ? (XMPP_ROSTER_RESOURCE_REC *)resource_list->data : NULL; } char * rosters_resolve_name(XMPP_SERVER_REC *server, const char *name) { XMPP_ROSTER_USER_REC *user; XMPP_ROSTER_RESOURCE_REC *resource; char *res, *str; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); g_return_val_if_fail(name != NULL, NULL); g_strstrip((char *)name); user = find_username(server->roster, name, NULL); if (user == NULL) user = rosters_find_user(server->roster, name, NULL, NULL); if (user != NULL) { if (!xmpp_have_resource(name)) { /* if unspecified, use the highest resource */ if (user->resources != NULL) { resource = user->resources->data; if (resource->name != NULL) return g_strconcat(user->jid, "/", resource->name, (void *)NULL); } return g_strdup(user->jid); } res = xmpp_extract_resource(name); str = g_strconcat(user->jid, "/", res, (void *)NULL); g_free(res); return str; } return NULL; } char * rosters_get_name(XMPP_SERVER_REC *server, const char *full_jid) { GSList *gl, *ul; XMPP_ROSTER_GROUP_REC *group; XMPP_ROSTER_USER_REC *user; char *jid; g_return_val_if_fail(IS_XMPP_SERVER(server), NULL); g_return_val_if_fail(full_jid != NULL, NULL); if ((jid = xmpp_strip_resource(full_jid)) == NULL) return NULL; for (gl = server->roster; gl != NULL; gl = gl->next) { group = gl->data; for (ul = group->users; ul != NULL; ul = ul->next) { user = ul->data; if (strcmp(jid, user->jid) == 0) { g_free(jid); return user->name; } } } g_free(jid); return NULL; } int xmpp_get_show(const char *show) { if (show != NULL && *show != '\0') { if (g_ascii_strcasecmp(show, xmpp_presence_show[XMPP_PRESENCE_CHAT]) == 0) return XMPP_PRESENCE_CHAT; else if (g_ascii_strcasecmp(show, xmpp_presence_show[XMPP_PRESENCE_DND]) == 0) return XMPP_PRESENCE_DND; else if (g_ascii_strcasecmp(show, xmpp_presence_show[XMPP_PRESENCE_XA]) == 0) return XMPP_PRESENCE_XA; else if (g_ascii_strcasecmp(show, xmpp_presence_show[XMPP_PRESENCE_AWAY]) == 0) return XMPP_PRESENCE_AWAY; else if (g_ascii_strcasecmp(show, xmpp_presence_show[XMPP_PRESENCE_ONLINE]) == 0) return XMPP_PRESENCE_AVAILABLE; } return XMPP_PRESENCE_AVAILABLE; } TODO0000644000175000017500000000271212261357644007364 0ustar fsfsNext release(s): - Fix IPv6 support - Assign threads to query windows - Implement bookmarks (to autojoin rooms) - Write the documentation in help/ for the commmands: ROSTER, PRESENCE, XMPPREGISTER, XMPPUNREGISTER, XMPPPASSWD - Handle errors and print errors messages (many errors are not handled yet, specially in MUC) - Rewrite completion (src/fe-common/xmpp-completion.c) - Add the commands /KICK and /BAN in MUCs - Implement the commands /SERVICES DISCOVER/LOGON/LOGOFF to print info/activate/deactivate a service (like a gateway) Delayed tasks: - Print name instead of jid in queries messages: One way to do it is to create new signals (like "message xmpp private" instead of "message private") and handle these new signals to print the nickname. The major problem is that you have to stop the signal "message private" to replace it with "message xmpp private", but many things in irssi handle the original signal so you have to recreate the same behaviors inside irssi-xmpp (which is complicated and boring). For inspiration you can see how the signal "message own_public" is handled in src/fe-common/fe-xmpp-messages.c The other (and better) way to do it, is to modify some signal emitted by irssi (at least "message private", to add a new parameter which will be the nick to display) and to modify the way irssi handle these new signals.