4 #include "icqcontacts.h"
5 #include "abstracthook.h"
7 #include "hooks/jabberhook.h"
14 #include <libotr/privkey.h>
15 #include <libotr/proto.h>
16 #include <libotr/message.h>
17 #include <libotr/userstate.h>
28 static OtrlPolicy
policy_cb(void *opdata
, ConnContext
*context
)
31 // face.log(_("[OTR-DEBUG] policy_cb(...) - returning OTRL_POLICY_DEFAULT"));
33 return OTRL_POLICY_DEFAULT
; // TODO: add user specific policies
35 return (OTRL_POLICY_ALLOW_V2
| OTRL_POLICY_REQUIRE_ENCRYPTION
| OTRL_POLICY_SEND_WHITESPACE_TAG
|
36 OTRL_POLICY_WHITESPACE_START_AKE
| OTRL_POLICY_ERROR_START_AKE
);
40 static void create_privkey_cb(void *opdata
, const char *accountname
,
44 face
.log("[OTR-DEBUG] create_privkey_cb(..., " + string(accountname
) + ")");
47 otrl_privkey_generate(otr
.get_userstate(), (string(conf
->getdirname()) + PRIVKEYFNAME
).c_str(), accountname
, protocol
);
49 // gaim-otr: otrg_ui_update_fingerprint();
53 static int is_logged_in_cb(void *opdata
, const char *accountname
, const char *protocol
, const char *recipient
)
56 string recipientname
= recipient
;
57 recipientname
= recipientname
.substr(0, recipientname
.find_last_of('/')); // removing "/<instandmessager>"
59 if (c
= clist
.get(imcontact(recipientname
, jabber
)))
61 if (c
->getstatus() == offline
)
64 face
.log("[OTR-DEBUG] is_logged_in_cb(..., " + string(accountname
) + ", " + string(protocol
)+ ", " + string(recipient
) + ") - returning 0");
66 return 0; // 0: offline
70 face
.log("[OTR-DEBUG] is_logged_in_cb(..., " + string(accountname
) + ", " + string(protocol
)+ ", " + string(recipient
) + ") - returning 1");
72 return 1; // 1: online
75 { // recipient not found in contact list
77 face
.log("[OTR-DEBUG] is_logged_in_cb(..., " + string(accountname
) + ", " + string(protocol
)+ ", " + string(recipient
) + ") - returning -1");
79 return -1; // -1: no idea if he's online...
84 static void inject_message_cb(void *opdata
, const char *accountname
, const char *protocol
, const char *recipient
, const char *message
)
87 string recipientname
= recipient
;
88 recipientname
= recipientname
.substr(0, recipientname
.find_last_of('/')); // removing "/<instandmessager>"
91 face
.log("[OTR-DEBUG] inject_message_cp(" + string(accountname
) + ", " + string(protocol
) + ", " + recipientname
+ ", " + string(message
) + ")");
94 if (c
= clist
.get(imcontact(recipientname
, jabber
)))
96 jhook
.send(immessage(c
->getdesc(), imevent::outgoing
, string(message
)));
99 face
.log(_("[OTR] Error: inject_message_cb, recipient \"") + recipientname
+ _("\" not found"));
104 static void notify_cb(void *opdata
, OtrlNotifyLevel level
,
105 const char *accountname
, const char *protocol
, const char *username
,
106 const char *title
, const char *primary
, const char *secondary
)
107 { // Display a notification message for a particular accountname / protocol / username conversation.
109 face
.log("[OTR-DEBUG] notify_cb");
111 string notify_level
= "";
114 case OTRL_NOTIFY_ERROR
: notify_level
= _("Error");
116 case OTRL_NOTIFY_WARNING
: notify_level
= _("Warning");
118 case OTRL_NOTIFY_INFO
: notify_level
= _("Info");
121 face
.log("[OTR] " + notify_level
);
122 if (accountname
) face
.log(_(" accountname: ") + string(accountname
));
123 if (protocol
) face
.log(_(" protocol: ") + string(protocol
));
124 if (username
) face
.log(_(" username: ") + string(username
));
125 if (title
) face
.log(_(" title: ") + string(title
));
126 if (primary
) face
.log(_(" primary: ") + string(primary
));
127 if (secondary
) face
.log(_(" secondary: ") + string(secondary
));
131 static int display_otr_message_cb(void *opdata
, const char *accountname
,
132 const char *protocol
, const char *username
, const char *msg
)
133 { /* Display an OTR control message for a particular accountname /
134 * protocol / username conversation. Return 0 if you are able to
135 * successfully display it. If you return non-0 (or if this
136 * function is NULL), the control message will be displayed inline,
137 * as a received message, or else by using the above notify()
140 face
.log("[OTR-DEBUG] display_otr_message_cb(...) - returning -1");
146 static void update_context_list_cb(void *opdata
)
147 { /* When the list of ConnContexts changes (including a change in
148 * state), this is called so the UI can be updated. */
150 face
.log("[OTR-DEBUG] update_context_list_cb(...)");
155 static const char *protocol_name_cb(void *opdata
, const char *protocol
)
156 { /* Return a newly-allocated string containing a human-friendly name
157 * for the given protocol id */
159 face
.log("[OTR-DEBUG] protocol_name_cb(...) - returning NULL");
165 static void protocol_name_free_cb(void *opdata
, const char *protocol_name
)
166 { // Deallocate a string allocated by protocol_name
167 // Do nothing, since we didn't actually allocate any memory in protocol_name_cb.
169 face
.log("[OTR-DEBUG] protocol_name_free_cb");
174 static void confirm_fingerprint_cb(void *opdata
, OtrlUserState us
,
175 const char *accountname
, const char *protocol
, const char *username
,
176 unsigned char fingerprint
[20])
177 { // A new fingerprint for the given user has been received.
179 face
.log("[OTR-DEBUG] confirm_fingerprint_cb");
181 face
.log(_("[OTR] Received unknown fingerprint from \"") + string(username
) + "\".");
182 face
.log(_(" You can verify it in the OTR options."));
186 static void write_fingerprints()
188 otrl_privkey_write_fingerprints(otr
.get_userstate(), (string(conf
->getdirname()) + STOREFNAME
).c_str());
191 static void write_fingerprints_cb(void *opdata
)
192 { // The list of known fingerprints has changed. Write them to disk.
194 face
.log("[OTR-DEBUG] write_fingerprints_cb");
196 write_fingerprints();
200 static void gone_secure_cb(void *opdata
, ConnContext
*context
)
201 { // A ConnContext has entered a secure state.
203 face
.log("[OTR-DEBUG] gone_secure_cb");
205 face
.log(_("[OTR] Connection is now secure..."));
209 static void gone_insecure_cb(void *opdata
, ConnContext
*context
)
210 { // A ConnContext has left a secure state.
212 face
.log("[OTR-DEBUG] gone_insecure_cb");
214 face
.log(_("[OTR] Connection is insecure..."));
218 static void still_secure_cb(void *opdata
, ConnContext
*context
, int is_reply
)
219 { /* We have completed an authentication, using the D-H keys we
220 * already knew. is_reply indicates whether we initiated the AKE. */
222 face
.log("[OTR-DEBUG] still_secure_cb");
227 static void log_message_cb(void *opdata
, const char *message
)
228 { // Log a message. The passed message will end in "\n".
230 face
.log("[OTR-DEBUG] log_message_cb(..., " + string(message
) + ")");
232 face
.log(_("[OTR] Log: ") + string(message
));
236 static OtrlMessageAppOps ui_ops
=
243 display_otr_message_cb
,
244 update_context_list_cb
,
246 protocol_name_free_cb
,
247 confirm_fingerprint_cb
,
248 write_fingerprints_cb
,
262 OTRL_INIT
; // Initialize the OTR library
264 userstate
= otrl_userstate_create(); // Make our OtrlUserState; we'll only use the one.
267 otrl_privkey_read(userstate
, (string(conf
->getdirname()) + PRIVKEYFNAME
).c_str());
268 otrl_privkey_read_fingerprints(userstate
, (string(conf
->getdirname()) + STOREFNAME
).c_str(), NULL
, NULL
);
280 otrl_userstate_free(userstate
);
284 OtrlUserState
imotr::get_userstate()
291 bool imotr::send_message(const protocolname pname
, const string
&recipient
, string
&text
)
293 if (pname
!= jabber
) // at the moment, otr is only with jabber supported...
298 gcry_error_t err
= 0;
299 char *newmessage
= NULL
;
301 string accountname
= conf
->getourid(pname
).nickname
+ "@" + conf
->getourid(pname
).server
;
302 string protocolname
= "jabber";
305 face
.log("[OTR-DEBUG] otrl_message_sending(" + accountname
+ ", " + protocolname
+ ", " + recipient
+ ", " + text
+ ")");
307 if (otrl_proto_message_type(text
.c_str()) == OTRL_MSGTYPE_NOTOTR
)
309 err
= otrl_message_sending(userstate
, &ui_ops
, NULL
, accountname
.c_str(), protocolname
.c_str(),
310 recipient
.c_str(), text
.c_str(), NULL
, &newmessage
, NULL
, NULL
);
314 face
.log(_("[OTR] Error while encrypting message... no message sent!"));
315 face
.log(_(" accountname: ") + accountname
);
316 face
.log(_(" recipient: ") + recipient
);
317 if (newmessage
) otrl_message_free(newmessage
);
326 face
.log("[OTR-DEBUG] otrl_message_sending - newmessage: \"" + text
+ "\")");
328 otrl_message_free(newmessage
);
335 bool imotr::receive_message(const protocolname pname
, const string
&from
, string
&text
)
337 if (pname
!= jabber
) // at the moment, otr is only with jabber supported...
343 char *newmessage
= NULL
;
345 string accountname
= conf
->getourid(pname
).nickname
+ "@" + conf
->getourid(pname
).server
;
346 string protocolname
= "jabber";
347 string sendername
= from
.substr(0, from
.find_last_of('/')); // remove "/<im-name>"
350 face
.log("[OTR-DEBUG] otrl_message_receive(" + accountname
+ ", " + protocolname
+ ", " + sendername
+ ", " + text
+ ")");
353 ignore_message
= otrl_message_receiving(userstate
, &ui_ops
, NULL
, accountname
.c_str(), protocolname
.c_str(),
354 sendername
.c_str(), text
.c_str(), &newmessage
, NULL
, NULL
, NULL
);
356 if (ignore_message
== 1) return false;
357 if (newmessage
== NULL
) return true;
362 face
.log("[OTR-DEBUG] otrl_message_sending - newmessage: \"" + text
+ "\")");
365 otrl_message_free(newmessage
);
371 void imotr::start_session(icqcontact
*contact
)
374 face
.log("[OTR-DEBUG] imotr::start_session(contact)");
376 if (contact
->getdesc().pname
!= jabber
) // at the moment, otr is only with jabber supported...
378 face
.log(_("[OTR] Error: At the moment, only jabber is supported"));
381 ConnContext
*context
;
382 string accountname
= conf
->getourid(contact
->getdesc().pname
).nickname
+ "@" + conf
->getourid(contact
->getdesc().pname
).server
;
383 string protocolname
= "jabber";
384 string username
= contact
->getdesc().nickname
;
386 face
.log(_("[OTR] Trying to start a secure session with \"") + username
+"\"...");
387 inject_message_cb(NULL
, accountname
.c_str(), protocolname
.c_str(), username
.c_str(), "?OTRv2?");
390 void imotr::end_session(icqcontact
*contact
)
393 face
.log("[OTR-DEBUG] imotr::end_session(contact)");
395 if (contact
->getdesc().pname
!= jabber
) // at the moment, otr is only with jabber supported...
397 face
.log(_("[OTR] Error: At the moment, only jabber is supported"));
400 ConnContext
*context
;
401 string accountname
= conf
->getourid(contact
->getdesc().pname
).nickname
+ "@" + conf
->getourid(contact
->getdesc().pname
).server
;
402 string protocolname
= "jabber";
403 string username
= contact
->getdesc().nickname
;
405 face
.log(_("[OTR] Ending secure session with \"") + username
+"\"...");
406 otrl_message_disconnect(userstate
, &ui_ops
, NULL
, accountname
.c_str(), protocolname
.c_str(), username
.c_str());
410 int imotr::yesno(const char *question
)
413 tmp
= face
.inputstr(" " + string(question
) + _("yes/no") + " ", _("no"));
414 while ((face
.getlastinputkey() != KEY_ESC
) && (tmp
!= _("yes")) && (tmp
!= _("no")))
416 tmp
= face
.inputstr(_(" Please type 'yes' or 'no': "), _("no"));
418 if (face
.getlastinputkey() == KEY_ESC
) return -1;
419 if (tmp
== _("yes")) return 1;
420 if (tmp
== _("no")) return 0;
428 int n
, b
, citem
, node
;
433 vector
< pair
< int, void* > > action
;
435 face
.blockmainscreen();
437 db
.setwindow(new textwindow(0, 0, face
.sizeDlg
.width
, face
.sizeDlg
.height
,
438 conf
->getcolor(cp_dialog_frame
), TW_CENTERED
,
439 conf
->getcolor(cp_dialog_highlight
), _(" IM account manager ")));
441 db
.settree(new treeview(conf
->getcolor(cp_dialog_text
), conf
->getcolor(cp_dialog_selected
),
442 conf
->getcolor(cp_dialog_highlight
), conf
->getcolor(cp_dialog_text
)));
444 db
.setbar(new horizontalbar(conf
->getcolor(cp_dialog_text
),
445 conf
->getcolor(cp_dialog_selected
), _("Change"), _("Done"), 0));
448 db
.idle
= &face
.dialogidle
;
450 treeview
&t
= *db
.gettree();
452 map
<protocolname
, bool> mod
;
453 for(protocolname pname
= icq
; pname
!= protocolname_size
; pname
++)
456 for(fin
= false; !fin
; ) {
462 node
= t
.addnode(0, 0, 0, _(" Private keys "));
463 for (OtrlPrivKey
*privkey
= userstate
->privkey_root
; privkey
!= NULL
; privkey
= privkey
->next
)
465 string accountname
= privkey
->accountname
;
466 string protocol
= privkey
->protocol
;
468 if (!otrl_privkey_fingerprint(userstate
, hash
, accountname
.c_str(), protocol
.c_str()))
470 strncpy(hash
, _("Error calculating Fingerprint"), 45);
472 n
= t
.addnode(node
, 0, 0, (_(" Account: ") + accountname
+ " ").c_str());
473 t
.addleaff(n
, 0, 0, (_(" Protocol: ") + protocol
+ " ").c_str());
474 t
.addleaff(n
, 0, 0, (_(" Fingerprint: ") + string(hash
) + " ").c_str());
475 t
.addleaff(n
, 0, citem
++, _(" Forget key "));
476 action
.push_back(pair
<int, void*>(0x100, privkey
));
477 // t.addleaff(n, 0, citem++, " Generate new key ");
478 // action.push_back(pair<int, void*>(0x101, privkey));
479 } // for (all privkeys)
481 node
= t
.addnode(0, 0, 0, _(" Public keys "));
482 for (ConnContext
*context
= userstate
->context_root
; context
!= NULL
; context
= context
->next
)
485 string username
= context
->username
;
486 string accountname
= context
->accountname
;
487 string protocol
= context
->protocol
;
488 n
= t
.addnode(node
, 0, 0, (_(" User: ") + username
+ " ").c_str());
489 t
.addleaff(n
, 0, 0, (_(" Protocol: ") + protocol
+ " ").c_str());
490 t
.addleaff(n
, 0, 0, (_(" Account: ") + accountname
+ " ").c_str());
492 for (Fingerprint
*fingerprint
= context
->fingerprint_root
.next
; fingerprint
!= NULL
; fingerprint
= fingerprint
->next
)
495 string verified
= (fingerprint
->trust
&& (string(fingerprint
->trust
) == "yes")) ? _("Yes") : _("No");
497 otrl_privkey_hash_to_human(hash
, fingerprint
->fingerprint
);
498 newnode
= t
.addnode(n
, 0, 0, (_(" Fingerprint: ") + string(hash
) + " ").c_str());
499 t
.addleaff(newnode
, 0, citem
++, (_(" Verified: ") + verified
).c_str());
500 action
.push_back(pair
<int, void*>(0x200, fingerprint
));
501 t
.addleaff(newnode
, 0, citem
++, _(" Forget key "));
502 action
.push_back(pair
<int, void*>(0x201, fingerprint
));
504 if (context
->active_fingerprint
)
506 otrl_privkey_hash_to_human(hash
, context
->active_fingerprint
->fingerprint
);
507 t
.addleaff(n
, 0, 0, (_(" Active fingerprint: ") + string(hash
) + " ").c_str());
514 fin
= !db
.open(n
, b
, (void **) &citem
) || (b
== 1);
520 switch (action
[citem
].first
)
522 case (0x100): // forget privkey
523 answer
= yesno(_("Do you want to forget the selected key?"));
526 otrl_privkey_forget((OtrlPrivKey
*)action
[citem
].second
);
527 write_fingerprints();
531 case (0x101): // generate new privkey
535 case (0x200): // verify fingerprint
536 answer
= yesno(_("Do you want verify the selected key?"));
537 if (answer
== -1) break;
538 otrl_context_set_trust((Fingerprint
*)action
[citem
].second
, ((answer
) ? "yes" : "no"));
539 write_fingerprints();
542 case (0x201): // forget fingerprint
543 answer
= yesno(_("Do you want to forget the selected key?"));
546 otrl_context_forget_fingerprint((Fingerprint
*)action
[citem
].second
, 1);
547 write_fingerprints();
559 face
.unblockmainscreen();
561 face
.relaxedupdate();
566 string
imotr::get_msg_state(const protocolname pname
, const string user
)
568 if (pname
!= jabber
) // at the moment, otr is only with jabber supported...
570 return _("No Jabber");
572 ConnContext
*context
;
573 string accountname
= conf
->getourid(pname
).nickname
+ "@" + conf
->getourid(pname
).server
;
574 string protocolname
= "jabber";
576 context
= otrl_context_find(userstate
, user
.c_str(), accountname
.c_str(), protocolname
.c_str(),
577 0, NULL
, NULL
, NULL
);
583 switch (context
->msgstate
)
585 case (OTRL_MSGSTATE_PLAINTEXT
): return _("Plaintext");
586 case (OTRL_MSGSTATE_ENCRYPTED
): return _("Encrypted");
587 case (OTRL_MSGSTATE_FINISHED
): return _("Finished");
588 default: return _("Unknown");
593 string
imotr::is_verified(const protocolname pname
, const string user
)
595 if (pname
!= jabber
) // at the moment, otr is only with jabber supported...
597 return _("No Jabber");
599 ConnContext
*context
;
600 string accountname
= conf
->getourid(pname
).nickname
+ "@" + conf
->getourid(pname
).server
;
601 string protocolname
= "jabber";
603 context
= otrl_context_find(userstate
, user
.c_str(), accountname
.c_str(), protocolname
.c_str(),
604 0, NULL
, NULL
, NULL
);
609 if (context
->active_fingerprint
== NULL
)
611 return _("No Encryption");
613 if (string(context
->active_fingerprint
->trust
) == "yes")
615 return _("Verified");
617 return _("Unverified");