1 /*
2  * client_events.c
3  * vim: expandtab:ts=4:sts=4:sw=4
4  *
5  * Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
6  * Copyright (C) 2019 - 2021 Michael Vetter <jubalh@iodoru.org>
7  *
8  * This file is part of Profanity.
9  *
10  * Profanity is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Profanity is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Profanity.  If not, see <https://www.gnu.org/licenses/>.
22  *
23  * In addition, as a special exception, the copyright holders give permission to
24  * link the code of portions of this program with the OpenSSL library under
25  * certain conditions as described in each individual source file, and
26  * distribute linked combinations including the two.
27  *
28  * You must obey the GNU General Public License in all respects for all of the
29  * code used other than OpenSSL. If you modify file(s) with this exception, you
30  * may extend this exception to your version of the file(s), but you are not
31  * obligated to do so. If you do not wish to do so, delete this exception
32  * statement from your version. If you delete this exception statement from all
33  * source files in the program, then also delete it here.
34  *
35  */
36 
37 #include "config.h"
38 
39 #include <stdlib.h>
40 #include <glib.h>
41 
42 #include "log.h"
43 #include "database.h"
44 #include "config/preferences.h"
45 #include "event/common.h"
46 #include "plugins/plugins.h"
47 #include "ui/window_list.h"
48 #include "xmpp/chat_session.h"
49 #include "xmpp/xmpp.h"
50 
51 #ifdef HAVE_LIBOTR
52 #include "otr/otr.h"
53 #endif
54 
55 #ifdef HAVE_LIBGPGME
56 #include "pgp/gpg.h"
57 #endif
58 
59 #ifdef HAVE_OMEMO
60 #include "omemo/omemo.h"
61 #endif
62 
63 jabber_conn_status_t
cl_ev_connect_jid(const char * const jid,const char * const passwd,const char * const altdomain,const int port,const char * const tls_policy,const char * const auth_policy)64 cl_ev_connect_jid(const char* const jid, const char* const passwd, const char* const altdomain, const int port, const char* const tls_policy, const char* const auth_policy)
65 {
66     cons_show("Connecting as %s", jid);
67     return session_connect_with_details(jid, passwd, altdomain, port, tls_policy, auth_policy);
68 }
69 
70 jabber_conn_status_t
cl_ev_connect_account(ProfAccount * account)71 cl_ev_connect_account(ProfAccount* account)
72 {
73     if (account->resource) {
74         cons_show("Connecting with account %s as %s/%s", account->name, account->jid, account->resource);
75     } else if (g_strcmp0(account->name, account->jid) == 0) {
76         cons_show("Connecting with account %s", account->name);
77     } else {
78         cons_show("Connecting with account %s as %s", account->name, account->jid);
79     }
80 
81     return session_connect_with_account(account);
82 }
83 
84 void
cl_ev_disconnect(void)85 cl_ev_disconnect(void)
86 {
87     char* mybarejid = connection_get_barejid();
88     cons_show("%s logged out successfully.", mybarejid);
89     free(mybarejid);
90 
91     ui_close_all_wins();
92     ev_disconnect_cleanup();
93     // on intentional disconnect reset the counter
94     ev_reset_connection_counter();
95 }
96 
97 void
cl_ev_presence_send(const resource_presence_t presence_type,const int idle_secs)98 cl_ev_presence_send(const resource_presence_t presence_type, const int idle_secs)
99 {
100     char* signed_status = NULL;
101 
102 #ifdef HAVE_LIBGPGME
103     char* account_name = session_get_account_name();
104     ProfAccount* account = accounts_get_account(account_name);
105     if (account->pgp_keyid) {
106         char* msg = connection_get_presence_msg();
107         signed_status = p_gpg_sign(msg, account->pgp_keyid);
108     }
109     account_free(account);
110 #endif
111 
112     presence_send(presence_type, idle_secs, signed_status);
113 
114     free(signed_status);
115 }
116 
117 void
cl_ev_send_msg_correct(ProfChatWin * chatwin,const char * const msg,const char * const oob_url,gboolean correct_last_msg)118 cl_ev_send_msg_correct(ProfChatWin* chatwin, const char* const msg, const char* const oob_url, gboolean correct_last_msg)
119 {
120     chat_state_active(chatwin->state);
121 
122     gboolean request_receipt = prefs_get_boolean(PREF_RECEIPTS_REQUEST);
123 
124     char* plugin_msg = plugins_pre_chat_message_send(chatwin->barejid, msg);
125     if (plugin_msg == NULL) {
126         return;
127     }
128 
129     char* replace_id = NULL;
130     if (correct_last_msg) {
131         replace_id = chatwin->last_msg_id;
132     }
133 
134     if (chatwin->is_omemo) {
135 #ifdef HAVE_OMEMO
136         char* id = omemo_on_message_send((ProfWin*)chatwin, plugin_msg, request_receipt, FALSE, replace_id);
137         if (id != NULL) {
138             chat_log_omemo_msg_out(chatwin->barejid, plugin_msg, NULL);
139             log_database_add_outgoing_chat(id, chatwin->barejid, plugin_msg, replace_id, PROF_MSG_ENC_OMEMO);
140             chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_OMEMO, request_receipt, replace_id);
141             free(id);
142         }
143 #endif
144     } else if (chatwin->is_ox) {
145 #ifdef HAVE_LIBGPGME
146         // XEP-0373: OpenPGP for XMPP
147         char* id = message_send_chat_ox(chatwin->barejid, plugin_msg, request_receipt, replace_id);
148         if (id != NULL) {
149             chat_log_pgp_msg_out(chatwin->barejid, plugin_msg, NULL);
150             log_database_add_outgoing_chat(id, chatwin->barejid, plugin_msg, replace_id, PROF_MSG_ENC_OX);
151             chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_OX, request_receipt, replace_id);
152             free(id);
153         }
154 #endif
155     } else if (chatwin->pgp_send) {
156 #ifdef HAVE_LIBGPGME
157         char* id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt, replace_id);
158         if (id != NULL) {
159             chat_log_pgp_msg_out(chatwin->barejid, plugin_msg, NULL);
160             log_database_add_outgoing_chat(id, chatwin->barejid, plugin_msg, replace_id, PROF_MSG_ENC_PGP);
161             chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PGP, request_receipt, replace_id);
162             free(id);
163         }
164 #endif
165     } else {
166         gboolean handled = FALSE;
167 #ifdef HAVE_LIBOTR
168         handled = otr_on_message_send(chatwin, plugin_msg, request_receipt, replace_id);
169 #endif
170         if (!handled) {
171             char* id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt, replace_id);
172             chat_log_msg_out(chatwin->barejid, plugin_msg, NULL);
173             log_database_add_outgoing_chat(id, chatwin->barejid, plugin_msg, replace_id, PROF_MSG_ENC_NONE);
174             chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_NONE, request_receipt, replace_id);
175             free(id);
176         }
177     }
178 
179     plugins_post_chat_message_send(chatwin->barejid, plugin_msg);
180     free(plugin_msg);
181     return;
182 }
183 
184 void
cl_ev_send_msg(ProfChatWin * chatwin,const char * const msg,const char * const oob_url)185 cl_ev_send_msg(ProfChatWin* chatwin, const char* const msg, const char* const oob_url)
186 {
187     cl_ev_send_msg_correct(chatwin, msg, oob_url, FALSE);
188 }
189 
190 void
cl_ev_send_muc_msg_corrected(ProfMucWin * mucwin,const char * const msg,const char * const oob_url,gboolean correct_last_msg)191 cl_ev_send_muc_msg_corrected(ProfMucWin* mucwin, const char* const msg, const char* const oob_url, gboolean correct_last_msg)
192 {
193     char* plugin_msg = plugins_pre_room_message_send(mucwin->roomjid, msg);
194     if (plugin_msg == NULL) {
195         return;
196     }
197 
198     char* replace_id = NULL;
199     if (correct_last_msg) {
200         replace_id = mucwin->last_msg_id;
201     }
202 
203 #ifdef HAVE_OMEMO
204     if (mucwin->is_omemo) {
205         char* id = omemo_on_message_send((ProfWin*)mucwin, plugin_msg, FALSE, TRUE, replace_id);
206         groupchat_log_omemo_msg_out(mucwin->roomjid, plugin_msg);
207         log_database_add_outgoing_muc(id, mucwin->roomjid, plugin_msg, replace_id, PROF_MSG_ENC_OMEMO);
208         mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_ENC_OMEMO, replace_id);
209         free(id);
210     } else {
211         char* id = message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url, replace_id);
212         groupchat_log_msg_out(mucwin->roomjid, plugin_msg);
213         log_database_add_outgoing_muc(id, mucwin->roomjid, plugin_msg, replace_id, PROF_MSG_ENC_NONE);
214         mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_ENC_NONE, replace_id);
215         free(id);
216     }
217 
218     plugins_post_room_message_send(mucwin->roomjid, plugin_msg);
219     free(plugin_msg);
220     return;
221 #endif
222 
223 #ifndef HAVE_OMEMO
224     char* id = message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url, replace_id);
225     groupchat_log_msg_out(mucwin->roomjid, plugin_msg);
226     log_database_add_outgoing_muc(id, mucwin->roomjid, plugin_msg, replace_id, PROF_MSG_ENC_NONE);
227     mucwin_outgoing_msg(mucwin, plugin_msg, id, PROF_MSG_ENC_NONE, replace_id);
228     free(id);
229 
230     plugins_post_room_message_send(mucwin->roomjid, plugin_msg);
231     free(plugin_msg);
232     return;
233 #endif
234 }
235 
236 void
cl_ev_send_muc_msg(ProfMucWin * mucwin,const char * const msg,const char * const oob_url)237 cl_ev_send_muc_msg(ProfMucWin* mucwin, const char* const msg, const char* const oob_url)
238 {
239     cl_ev_send_muc_msg_corrected(mucwin, msg, oob_url, FALSE);
240 }
241 
242 void
cl_ev_send_priv_msg(ProfPrivateWin * privwin,const char * const msg,const char * const oob_url)243 cl_ev_send_priv_msg(ProfPrivateWin* privwin, const char* const msg, const char* const oob_url)
244 {
245     if (privwin->occupant_offline) {
246         privwin_message_occupant_offline(privwin);
247     } else if (privwin->room_left) {
248         privwin_message_left_room(privwin);
249     } else {
250         char* plugin_msg = plugins_pre_priv_message_send(privwin->fulljid, msg);
251         Jid* jidp = jid_create(privwin->fulljid);
252 
253         char* id = message_send_private(privwin->fulljid, plugin_msg, oob_url);
254         chat_log_msg_out(jidp->barejid, plugin_msg, jidp->resourcepart);
255         log_database_add_outgoing_muc_pm(id, privwin->fulljid, plugin_msg, NULL, PROF_MSG_ENC_NONE);
256         privwin_outgoing_msg(privwin, plugin_msg);
257         free(id);
258 
259         plugins_post_priv_message_send(privwin->fulljid, plugin_msg);
260 
261         free(plugin_msg);
262         jid_destroy(jidp);
263     }
264 }
265