1 #include "internal.h"
2 
3 #include <string.h>
4 #include <ctype.h>
5 
6 #include <gdk/gdk.h>
7 #include <gtk/gtkplug.h>
8 
9 #include <gtkplugin.h>
10 
11 #include <debug.h>
12 #include <util.h>
13 #include <conversation.h>
14 
15 #include "pe_blist.h"
16 #include "state_ui.h"
17 #include "state.h"
18 
19 GHashTable *encryption_state_table; /* name -> EncryptionState */
20 
21 /* Helper function: */
22 static void reset_state_struct(const PurpleAccount* account,
23                                const gchar* name,
24                                EncryptionState* state);
25 
26 void PE_state_init() {
27    encryption_state_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
28 }
29 
30 void PE_state_delete() {
31    g_hash_table_destroy(encryption_state_table);
32 }
33 
34 EncryptionState* PE_get_state(PurpleConversation* conv) {
35    if (conv == NULL) return NULL;
36 
37    EncryptionState *state = purple_conversation_get_data(conv, "PE_state");
38 
39    if (state == NULL) {
40       state = g_malloc(sizeof(EncryptionState));
41       purple_conversation_set_data(conv, "PE_state", state);
42 
43       // should probably change this to use some prefs info rather than our buddy list stuff
44       state->outgoing_encrypted =
45          PE_get_buddy_default_autoencrypt(purple_conversation_get_account(conv),
46                                           purple_conversation_get_name(conv));
47 
48       if (conv == NULL) {
49          return NULL;
50       }
51 
52       state->has_been_notified =
53          PE_get_default_notified(purple_conversation_get_account(conv),
54                                  purple_conversation_get_name(conv));
55 
56       state->incoming_encrypted = FALSE;
57       state->is_capable = FALSE;
58    }
59    return state;
60 }
61 
62 void PE_reset_state(PurpleConversation* conv) {
63    EncryptionState *state;
64 
65    if (conv == NULL) return;
66 
67    state = PE_get_state(conv);
68 
69    reset_state_struct(purple_conversation_get_account(conv), purple_conversation_get_name(conv), state);
70 }
71 
72 void PE_free_state(PurpleConversation* conv) {
73    EncryptionState *state;
74 
75    if (conv == NULL) return;
76 
77    state = PE_get_state(conv);
78 
79    if (state) {
80       g_free(state);
81    }
82 }
83 
84 static void reset_state_struct(const PurpleAccount* account, const gchar* name,
85                                EncryptionState* state) {
86 
87    state->outgoing_encrypted = PE_get_buddy_default_autoencrypt(account, name);
88    state->has_been_notified = PE_get_default_notified(account, name);
89 
90    state->incoming_encrypted = FALSE;
91    state->is_capable = FALSE;
92 }
93 
94 void PE_set_tx_encryption(PurpleConversation* conv, gboolean do_encrypt) {
95    EncryptionState *state;
96 
97    if (conv == NULL) return;
98 
99    state = PE_get_state(conv);
100 
101    if (state->outgoing_encrypted != do_encrypt) {
102       state->outgoing_encrypted = do_encrypt;
103       PE_sync_state(conv);
104    }
105 }
106 
107 void PE_set_capable(PurpleConversation* conv, gboolean cap) {
108    EncryptionState *state;
109 
110    if (conv == NULL) return;
111 
112    state = PE_get_state(conv);
113 
114    if (state->is_capable != cap) {
115       state->is_capable = cap;
116       if (state->outgoing_encrypted == FALSE) {
117          PE_sync_state(conv);
118       }
119    }
120 }
121 
122 void PE_set_rx_encryption(PurpleConversation *conv, gboolean incoming_encrypted) {
123    EncryptionState *state;
124 
125    if (conv == NULL) return;
126 
127    state = PE_get_state(conv);
128 
129    if (state->incoming_encrypted != incoming_encrypted) {
130       state->incoming_encrypted = incoming_encrypted;
131       PE_set_rx_encryption_icon(conv, incoming_encrypted);
132    }
133 }
134 
135 gboolean PE_get_tx_encryption(PurpleConversation *conv) {
136    EncryptionState *state = PE_get_state(conv);
137 
138    if (state == NULL) return FALSE;
139 
140    return state->outgoing_encrypted;
141 }
142 
143 void PE_sync_state(PurpleConversation *conv) {
144    EncryptionState *state;
145 
146    if (conv == NULL) return;
147 
148    state = PE_get_state(conv);
149    PE_set_rx_encryption_icon(conv, state->incoming_encrypted);
150    PE_set_tx_encryption_icon(conv, state->outgoing_encrypted, state->is_capable);
151 }
152 
153 gboolean PE_has_been_notified(PurpleConversation *conv) {
154    EncryptionState *state = PE_get_state(conv);
155 
156    if (state == NULL) return TRUE;
157 
158    return state->has_been_notified;
159 }
160 
161 void PE_set_notified(PurpleConversation *conv, gboolean new_state) {
162    EncryptionState *state;
163 
164    if (conv == NULL) return;
165 
166    state = PE_get_state(conv);
167 
168    state->has_been_notified = new_state;
169 }
170 
171 
172 gboolean PE_get_default_notified(const PurpleAccount *account, const gchar* name) {
173    /* Most protocols no longer have a notify message, since they don't do HTML */
174 
175    /* The only special case here is Oscar/TOC: If the other user's name is all */
176    /* digits, then they're ICQ, so we pretend that we already notified them    */
177 
178    const char* protocol_id = purple_account_get_protocol_id(account);
179 
180    if (strcmp(protocol_id, "prpl-toc") == 0 || strcmp(protocol_id, "prpl-oscar") == 0) {
181 
182       while(*name != 0) {
183          if (!isdigit(*name++)) {
184             /* not ICQ */
185             return FALSE;
186          }
187       }
188       /* Hrm.  must be ICQ */
189       return TRUE;
190    }
191 
192    /* default to notifying next time, if protocol allows it */
193 
194    return FALSE;
195 }
196 
197 
198