aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llimpanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llimpanel.cpp992
1 files changed, 989 insertions, 3 deletions
diff --git a/linden/indra/newview/llimpanel.cpp b/linden/indra/newview/llimpanel.cpp
index 4953a27..85ab779 100644
--- a/linden/indra/newview/llimpanel.cpp
+++ b/linden/indra/newview/llimpanel.cpp
@@ -83,6 +83,14 @@
83#include "rlvhandler.h" 83#include "rlvhandler.h"
84// [/RLVa:KB] 84// [/RLVa:KB]
85 85
86#if USE_OTR // [$PLOTR$]
87#include "context.h"
88#include "llcombobox.h"
89#include "otr_wrapper.h"
90#include "otr_floater_smp_dialog.h"
91#include "otr_floater_smp_progress.h"
92#endif // USE_OTR // [/$PLOTR$]
93
86// 94//
87// Constants 95// Constants
88// 96//
@@ -1107,6 +1115,10 @@ LLFloaterIMPanel::LLFloaterIMPanel(
1107 mCallBackEnabled(TRUE), 1115 mCallBackEnabled(TRUE),
1108 mSpeakers(NULL), 1116 mSpeakers(NULL),
1109 mSpeakerPanel(NULL), 1117 mSpeakerPanel(NULL),
1118#if USE_OTR // [$PLOTR$]
1119 mOtrSmpDialog(NULL),
1120 mOtrSmpProgress(NULL),
1121#endif // USE_OTR // [/$PLOTR$]
1110 mFirstKeystrokeTimer(), 1122 mFirstKeystrokeTimer(),
1111 mLastKeystrokeTimer() 1123 mLastKeystrokeTimer()
1112{ 1124{
@@ -1140,6 +1152,10 @@ LLFloaterIMPanel::LLFloaterIMPanel(
1140 mCallBackEnabled(TRUE), 1152 mCallBackEnabled(TRUE),
1141 mSpeakers(NULL), 1153 mSpeakers(NULL),
1142 mSpeakerPanel(NULL), 1154 mSpeakerPanel(NULL),
1155#if USE_OTR // [$PLOTR$]
1156 mOtrSmpDialog(NULL),
1157 mOtrSmpProgress(NULL),
1158#endif // USE_OTR // [/$PLOTR$]
1143 mFirstKeystrokeTimer(), 1159 mFirstKeystrokeTimer(),
1144 mLastKeystrokeTimer(), 1160 mLastKeystrokeTimer(),
1145 mIMPanelType(IM_PANEL_PLAIN) 1161 mIMPanelType(IM_PANEL_PLAIN)
@@ -1319,6 +1335,11 @@ LLFloaterIMPanel::~LLFloaterIMPanel()
1319 { 1335 {
1320 mInputEditor->setFocusLostCallback( NULL ); 1336 mInputEditor->setFocusLostCallback( NULL );
1321 } 1337 }
1338
1339#if USE_OTR // [$PLOTR$]
1340 if (mOtrSmpDialog) delete mOtrSmpDialog;
1341 if (mOtrSmpProgress) delete mOtrSmpProgress;
1342#endif // USE_OTR // [/$PLOTR$]
1322} 1343}
1323 1344
1324BOOL LLFloaterIMPanel::postBuild() 1345BOOL LLFloaterIMPanel::postBuild()
@@ -1388,6 +1409,27 @@ BOOL LLFloaterIMPanel::postBuild()
1388 childSetCommitCallback("speaker_volume", onVolumeChange, this); 1409 childSetCommitCallback("speaker_volume", onVolumeChange, this);
1389 } 1410 }
1390 1411
1412#if USE_OTR // [$PLOTR$]
1413 if (!gOTR) OTR_Wrapper::init();
1414 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
1415 {
1416 childSetCommitCallback("otr_btn", onClickOtr, this);
1417 LLComboBox *combo = getChild<LLComboBox>("otr_btn");
1418 if (!combo)
1419 {
1420 llwarns << "$PLOTR$ Can't find OTR control/status" << llendl;
1421 }
1422 else
1423 {
1424 llinfos << "$PLOTR$ found OTR control/status" << llendl;
1425 combo->setCommitCallback(onClickOtr);
1426 combo->setCallbackUserData(this);
1427 combo->setAllowTextEntry(FALSE, 0, FALSE);
1428 showOtrStatus();
1429 }
1430 }
1431#endif // USE_OTR // [/$PLOTR$]
1432
1391 setDefaultBtn("send_btn"); 1433 setDefaultBtn("send_btn");
1392 return TRUE; 1434 return TRUE;
1393 } 1435 }
@@ -1627,7 +1669,7 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4
1627 // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile. 1669 // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile.
1628 if (!name.empty()) // If name exists, then add it to the front of the message. 1670 if (!name.empty()) // If name exists, then add it to the front of the message.
1629 { 1671 {
1630 // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. 1672 // Don't hotlink any messages from the system, so just add those in plain text.
1631 if (name == SYSTEM_FROM) 1673 if (name == SYSTEM_FROM)
1632 { 1674 {
1633 mHistoryEditor->appendColoredText(name,false,prepend_newline,color); 1675 mHistoryEditor->appendColoredText(name,false,prepend_newline,color);
@@ -2119,6 +2161,778 @@ void deliver_message(const std::string& utf8_text,
2119 } 2161 }
2120} 2162}
2121 2163
2164#if USE_OTR // [$PLOTR$]
2165static bool g_otr_force_typing_stop = false; // ugly hack...
2166// sometimes we must send messages, but don't know if they are offline
2167
2168void otr_deliver_message(const std::string& utf8_text,
2169 const LLUUID& im_session_id,
2170 const LLUUID& other_participant_id,
2171 EInstantMessage dialog)
2172{
2173// llinfos
2174// << "$PLOTR$ message length:" << utf8_text.length()
2175// << " [" << utf8_text.substr(0, 24)
2176// << "]...[" << utf8_text.substr(utf8_text.length()-10, utf8_text.length()-1)
2177// << "]" << llendl;
2178 std::string name;
2179 gAgent.buildFullname(name);
2180
2181 const LLRelationship* info = NULL;
2182 info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id);
2183
2184 U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;
2185
2186 // default to IM_SESSION_SEND unless it's nothing special - in
2187 // which case it's probably an IM to everyone.
2188 U8 new_dialog = dialog;
2189
2190 if ( dialog != IM_NOTHING_SPECIAL )
2191 {
2192 new_dialog = IM_SESSION_SEND;
2193 }
2194 if ((new_dialog == IM_NOTHING_SPECIAL) &&
2195 (g_otr_force_typing_stop ||
2196 (gSavedSettings.getBOOL("EmeraldOTRInTypingStop"))))
2197 {
2198 OtrlMessageType mtype = otrl_proto_message_type(utf8_text.c_str());
2199 switch (mtype)
2200 {
2201 case OTRL_MSGTYPE_UNKNOWN:
2202 llwarns << "Sending unknown type of OTR message" << llendl;
2203 // fall through
2204 case OTRL_MSGTYPE_QUERY:
2205 case OTRL_MSGTYPE_DH_COMMIT:
2206 case OTRL_MSGTYPE_DH_KEY:
2207 case OTRL_MSGTYPE_REVEALSIG:
2208 case OTRL_MSGTYPE_SIGNATURE:
2209 case OTRL_MSGTYPE_V1_KEYEXCH:
2210 case OTRL_MSGTYPE_DATA:
2211 case OTRL_MSGTYPE_TAGGEDPLAINTEXT:
2212 new_dialog = IM_TYPING_STOP;
2213 break;
2214 case OTRL_MSGTYPE_NOTOTR:
2215 case OTRL_MSGTYPE_ERROR:
2216 default:
2217 /* new_dialog = IM_NOTHING_SPECIAL */ ;
2218 }
2219 }
2220 pack_instant_message(
2221 gMessageSystem,
2222 gAgent.getID(),
2223 FALSE,
2224 gAgent.getSessionID(),
2225 other_participant_id,
2226 name.c_str(),
2227 utf8_text.c_str(),
2228 offline,
2229 (EInstantMessage)new_dialog,
2230 im_session_id);
2231 gAgent.sendReliableMessage();
2232
2233 // If there is a mute list and this is not a group chat...
2234 if ( LLMuteList::getInstance() )
2235 {
2236 // ... the target should not be in our mute list for some message types.
2237 // Auto-remove them if present.
2238 switch( dialog )
2239 {
2240 case IM_NOTHING_SPECIAL:
2241 case IM_GROUP_INVITATION:
2242 case IM_INVENTORY_OFFERED:
2243 case IM_SESSION_INVITE:
2244 case IM_SESSION_P2P_INVITE:
2245 case IM_SESSION_CONFERENCE_START:
2246 case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing.
2247 case IM_LURE_USER:
2248 case IM_GODLIKE_LURE_USER:
2249 case IM_FRIENDSHIP_OFFERED:
2250 LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM);
2251 break;
2252 default: ; // do nothing
2253 }
2254 }
2255}
2256
2257// static
2258void LLFloaterIMPanel::onClickOtr(LLUICtrl* source, void* userdata)
2259{
2260 LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata;
2261 if (self)
2262 {
2263 self->doOtrMenu();
2264 self->showOtrStatus();
2265 }
2266 else
2267 {
2268 llwarns << "$PLOTR$ onClickOtr() can't find floater." << llendl;
2269 }
2270}
2271
2272void LLFloaterIMPanel::doOtrStart()
2273{
2274 U32 otrpref = gSavedSettings.getU32("EmeraldUseOTR");
2275 // otrpref: 0 == Require use of OTR in IMs, 1 == Request OTR if available, 2 == Accept OTR requests, 3 == Decline use of OTR
2276 if (3 == otrpref)
2277 {
2278 //otrLogMessageGetstring("otr_err_deacivated");
2279 showOtrStatus();
2280 return;
2281 }
2282 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2283 {
2284 llinfos << "$PLOTR$ otr menu start/restart/refresh" << llendl;
2285 gcry_error_t err = 0;
2286 char *newmessage = NULL;
2287 char my_uuid[UUID_STR_SIZE];
2288 char their_uuid[UUID_STR_SIZE];
2289 gAgent.getID().toString(&(my_uuid[0]));
2290 mOtherParticipantUUID.toString(&(their_uuid[0]));
2291
2292 const LLRelationship* info = NULL;
2293 info = LLAvatarTracker::instance().getBuddyInfo(mOtherParticipantUUID);
2294 if (info && (!info->isOnline()))
2295 {
2296 otrLogMessageGetstringName("otr_err_offline_start");
2297 return;
2298 }
2299
2300 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2301 {
2302 // only try OTR for 1 on 1 IM's
2303 err = otrl_message_sending(
2304 gOTR->get_userstate(),
2305 gOTR->get_uistate(),
2306 &mSessionUUID,
2307 my_uuid,
2308 gOTR->get_protocolid(),
2309 their_uuid,
2310 "?OTRv2?", NULL, &newmessage,
2311 NULL, NULL);
2312 }
2313 if (err)
2314 {
2315 llwarns << "$PLOTR$ OTR failed to encrypt start message" << llendl;
2316 otrLogMessageGetstring("otr_err_failed_starting");
2317 return;
2318 }
2319 else if (newmessage)
2320 {
2321 // OTR encrypted the message. Handle fragmentation of the message
2322 int context_added = 0;
2323 ConnContext *context = getOtrContext(1, &context_added);
2324 if (context_added)
2325 {
2326 llwarns << "$PLOTR$ context added *after* send start but before fragmentation." << llendl;
2327 }
2328 if (! context)
2329 {
2330 otrLogMessageGetstring("otr_err_failed_starting");
2331 llwarns << "$PLOTR$ can't find context, not sending start message." << llendl;
2332 return;
2333 }
2334 else
2335 {
2336 char *extrafragment = NULL;
2337 err = otrl_message_fragment_and_send(
2338 gOTR->get_uistate(),
2339 &mSessionUUID,
2340 context,
2341 newmessage,
2342 OTRL_FRAGMENT_SEND_ALL,
2343 &extrafragment);
2344 }
2345 if (newmessage) otrl_message_free(newmessage);
2346 //otrLogMessageGetstringName("otr_prog_I_start");
2347 }
2348 else
2349 {
2350 llwarns << "$PLOTR$ can't start OTR for some reason." << llendl;
2351 otrLogMessageGetstring("otr_err_failed_starting");
2352 return;
2353 }
2354 }
2355}
2356
2357void LLFloaterIMPanel::doOtrStop(bool pretend_they_did)
2358{
2359 llinfos << "$PLOTR$ otr menu stop 1" << llendl;
2360 // do not disable this bassed on gSavedSettings.getU32("EmeraldUseOTR");
2361 // when the user disables OTR we may still need to stop currently encrypted conversations
2362 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2363 {
2364 char my_uuid[UUID_STR_SIZE];
2365 char their_uuid[UUID_STR_SIZE];
2366 gAgent.getID().toString(&(my_uuid[0]));
2367 mOtherParticipantUUID.toString(&(their_uuid[0]));
2368 llinfos << "$PLOTR$ otr menu stop 2 their_uuid:" << mOtherParticipantUUID << llendl;
2369 g_otr_force_typing_stop = true; // ugly hack
2370 otrl_message_disconnect(
2371 gOTR->get_userstate(),
2372 gOTR->get_uistate(),
2373 &mSessionUUID,
2374 my_uuid,
2375 gOTR->get_protocolid(),
2376 their_uuid);
2377 g_otr_force_typing_stop = false;
2378 if (pretend_they_did)
2379 {
2380 otrLogMessageGetstringName("otr_prog_they_stop");
2381 }
2382 else
2383 {
2384 //otrLogMessageGetstringName("otr_prog_I_stop");
2385 }
2386 showOtrStatus();
2387 }
2388}
2389
2390void LLFloaterIMPanel::doOtrAuth()
2391{
2392 if (mOtrSmpDialog)
2393 {
2394 llinfos << "$PLOTR$ mOtrSmpDialog SMP already in progress, ignoring request to start it" << llendl;
2395 return;
2396 }
2397 if (mOtrSmpDialog || mOtrSmpProgress)
2398 {
2399 llinfos << "$PLOTR$ SMP already in progress, ignoring request to start it" << llendl;
2400 // $TODO$ Tell the user nicely to cancel the one in progress.
2401 // $TODO$ better yet, cancel it/them for the user
2402 return;
2403 }
2404 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2405 {
2406 llinfos << "$PLOTR$ otr menu auth" << llendl;
2407
2408 ConnContext *context = getOtrContext();
2409 if (!context)
2410 {
2411 llwarns << "$PLOTR$ doOtrAuth can't find context." << llendl;
2412 return;
2413 }
2414 char my_uuid[UUID_STR_SIZE];
2415 gAgent.getID().toString(&(my_uuid[0]));
2416 char my_fingerprint[45];
2417 otrl_privkey_fingerprint(gOTR->get_userstate(),
2418 my_fingerprint,
2419 my_uuid,
2420 gOTR->get_protocolid());
2421 char other_fingerprint[45];
2422 otrl_privkey_hash_to_human(other_fingerprint, context->active_fingerprint->fingerprint);
2423 startSmpDialog(mSessionUUID, mOtherParticipantUUID,
2424 &(my_fingerprint[0]), &(other_fingerprint[0]));
2425 }
2426}
2427
2428
2429void LLFloaterIMPanel::doOtrMenu()
2430{
2431 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2432 {
2433 LLComboBox *combo = getChild<LLComboBox>("otr_btn");
2434 if (!combo)
2435 {
2436 llwarns << "$PLOTR$ Can't find OTR control/status" << llendl;
2437 }
2438 else
2439 {
2440 ConnContext *context = getOtrContext();
2441 U32 otrpref = gSavedSettings.getU32("EmeraldUseOTR");
2442 if (combo->getValue().asString() == "otr_auth_entry")
2443 {
2444 // Instant crash when doing this with someone that has no OTR capability.
2445 // So guard it if no encryption is happening.
2446 if (context && (OTRL_MSGSTATE_ENCRYPTED == context->msgstate))
2447 {
2448 doOtrAuth();
2449 }
2450 }
2451 else if (combo->getValue().asString() == "otr_help_entry")
2452 {
2453 llinfos << "$PLOTR$ otr help" << llendl;
2454 LLWeb::loadURL("http://www.cypherpunks.ca/otr/");
2455 }
2456 else if (combo->getValue().asString() == "otr_levels_entry")
2457 {
2458 llinfos << "$PLOTR$ otr levels help" << llendl;
2459 LLWeb::loadURL("http://www.cypherpunks.ca/otr/help/3.2.0/levels.php");
2460 }
2461 else // Clicked the flyout itself. Sort out what level to put them in based on the old level.
2462 {
2463 // otrpref: 0 == Require OTR, 1 == Request OTR, 2 == Accept OTR, 3 == Decline OTR
2464 if (3 == otrpref)
2465 {
2466 if (context && (OTRL_MSGSTATE_ENCRYPTED == context->msgstate))
2467 {
2468 doOtrStop();
2469 }
2470 }
2471 else if (context && (OTRL_MSGSTATE_ENCRYPTED == context->msgstate))
2472 {
2473 doOtrStop();
2474 }
2475 else if (context && (OTRL_MSGSTATE_FINISHED == context->msgstate))
2476 {
2477 doOtrStop();
2478 }
2479 else // OTRL_MSGSTATE_PLAINTEXT, or no context yet
2480 {
2481 doOtrStart();
2482 }
2483 }
2484 }
2485 }
2486}
2487
2488ConnContext *LLFloaterIMPanel::getOtrContext(int create_if_not_found, int *context_added)
2489{
2490 ConnContext *context = NULL;
2491 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2492 {
2493 char my_uuid[UUID_STR_SIZE];
2494 char their_uuid[UUID_STR_SIZE];
2495 gAgent.getID().toString(&(my_uuid[0]));
2496 mOtherParticipantUUID.toString(&(their_uuid[0]));
2497 context = otrl_context_find(
2498 gOTR->get_userstate(),
2499 their_uuid,
2500 my_uuid,
2501 gOTR->get_protocolid(),
2502 create_if_not_found, context_added, NULL, NULL);
2503 }
2504 return context;
2505}
2506
2507bool LLFloaterIMPanel::otherIsOtrAuthenticated()
2508{
2509 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2510 {
2511 ConnContext *context = getOtrContext();
2512 if (context && context->active_fingerprint &&
2513 context->active_fingerprint->trust &&
2514 *(context->active_fingerprint->trust))
2515 {
2516 llinfos << "$PLOTR$ they are authenticated -- trust level is "
2517 << (context->active_fingerprint->trust) << llendl;
2518 return true;
2519 }
2520 }
2521 llinfos << "$PLOTR$ they are NOT authenticated" << llendl;
2522 return false;
2523}
2524
2525void LLFloaterIMPanel::showOtrStatus()
2526{
2527 if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
2528 {
2529 LLFlyoutButton *combo = (LLFlyoutButton *) getChild<LLComboBox>("otr_btn");
2530 if (!combo)
2531 {
2532 llerrs << "$PLOTR$ Can't find OTR control/status" << llendl;
2533 }
2534 else
2535 {
2536 ConnContext *context = getOtrContext();
2537 U32 otrpref = gSavedSettings.getU32("EmeraldUseOTR");
2538 // otrpref: 0 == Require OTR, 1 == Request OTR, 2 == Accept OTR, 3 == Decline OTR
2539 if (3 == otrpref)
2540 {
2541 if (context && (OTRL_MSGSTATE_ENCRYPTED == context->msgstate))
2542 {
2543 doOtrStop();
2544 }
2545 combo->setLabel(getString("otr_not_private"));
2546 }
2547 else if (context && (OTRL_MSGSTATE_ENCRYPTED == context->msgstate))
2548 {
2549 if (otherIsOtrAuthenticated())
2550 combo->setLabel(getString("otr_private"));
2551 else
2552 combo->setLabel(getString("otr_unverified"));
2553 }
2554 else if (context && (OTRL_MSGSTATE_FINISHED == context->msgstate))
2555 {
2556 if (OTRL_MSGSTATE_ENCRYPTED == mOtrLastStatus)
2557 {
2558 if (otherIsOtrAuthenticated())
2559 otrLogMessageGetstringName("otr_prog_they_stop_private");
2560 else
2561 otrLogMessageGetstringName("otr_prog_they_stop_unverified");
2562 }
2563 combo->setLabel(getString("otr_finished"));
2564 }
2565 else // OTRL_MSGSTATE_PLAINTEXT, or no context yet
2566 {
2567 combo->setLabel(getString("otr_not_private"));
2568 }
2569 if (context)
2570 {
2571 mOtrLastStatus = context->msgstate;
2572 }
2573 }
2574 }
2575}
2576
2577void LLFloaterIMPanel::otrLogMessage(std::string message)
2578{
2579 addHistoryLine(message, gSavedSettings.getColor("SystemChatColor"), true, mOtherParticipantUUID);
2580}
2581
2582void LLFloaterIMPanel::otrLogMessageGetstring(const char *message_name)
2583{
2584 LLUIString msg = getString(message_name);
2585 otrLogMessage(msg);
2586}
2587
2588void LLFloaterIMPanel::otrLogMessageGetstringName(const char *message_name)
2589{
2590 LLUIString msg = getString(message_name);
2591 std::string them;
2592 if (!gCacheName->getFullName(mOtherParticipantUUID, them)) them = getString("otr_generic_name");
2593 msg.setArg("[NAME]", them);
2594 otrLogMessage(msg);
2595}
2596
2597void otr_log_message(LLUUID session_id, const char *message)
2598{
2599 LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id);
2600 if (floater) floater->otrLogMessage(message);
2601 else
2602 {
2603 llinfos << "$PLOTR$ otr_log_message(" << message << ") failed to find floater." << llendl;
2604 }
2605}
2606
2607void otr_log_message_getstring(LLUUID session_id, const char *message_name)
2608{
2609 LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id);
2610 if (floater) floater->otrLogMessageGetstring(message_name);
2611 else
2612 {
2613 llinfos << "$PLOTR$ otr_log_message_getstring(" << message_name << ") failed to find floater." << llendl;
2614 }
2615}
2616
2617void otr_log_message_getstring_name(LLUUID session_id, const char *message_name)
2618{
2619 LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id);
2620 if (floater) floater->otrLogMessageGetstringName(message_name);
2621 else
2622 {
2623 llinfos << "$PLOTR$ otr_log_message_getstring_name(" << message_name << ") failed to find floater." << llendl;
2624 }
2625}
2626
2627void LLFloaterIMPanel::otrAuthenticateKey(const char *trust)
2628{
2629 int context_added = 0;
2630 ConnContext *context = getOtrContext(0, &context_added);
2631 if (gOTR && context)
2632 {
2633 otrl_context_set_trust(context->active_fingerprint, trust);
2634 otrLogMessageGetstringName("otr_log_authenticated");
2635 otrLogMessageGetstringName("otr_log_start_private");
2636 std::string pubpath =
2637 gDirUtilp->getExpandedFilename(
2638 LL_PATH_PER_SL_ACCOUNT, OTR_PUBLIC_KEYS_FILE);
2639 otrl_privkey_write_fingerprints(gOTR->get_userstate(), pubpath.c_str());
2640 showOtrStatus();
2641 }
2642}
2643
2644void otr_authenticate_key(LLUUID session_id, const char *trust)
2645{
2646 LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id);
2647 if (floater) floater->otrAuthenticateKey(trust);
2648 else
2649 {
2650 llinfos << "$PLOTR$ otr_authenticate_key(" << session_id << ", " << trust << ") failed to find floater." << llendl;
2651 }
2652}
2653
2654void otr_show_status(LLUUID session_id)
2655{
2656 LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(session_id);
2657 if (floater) floater->showOtrStatus();
2658 else
2659 {
2660 llinfos << "$PLOTR$ can't find floater." << llendl;
2661 }
2662}
2663
2664void LLFloaterIMPanel::pretendTheyOtrStop()
2665{
2666 llinfos << "$PLOTR$ pretending they did doOtrStop()" << llendl;
2667 // we really stop our end, but...
2668 doOtrStop(true); // ... pretend that they did it
2669 ConnContext *context = getOtrContext();
2670 if (context) context->msgstate = OTRL_MSGSTATE_FINISHED;
2671 else
2672 {
2673 llwarns << "$PLOTR$ can't find context." << llendl;
2674 }
2675 showOtrStatus();
2676}
2677
2678void LLFloaterIMPanel::startSmpDialog(
2679 LLUUID session_id, LLUUID other_id,
2680 std::string my_fingerprint, std::string other_fingerprint)
2681{
2682 if (mOtrSmpDialog)
2683 {
2684 mOtrSmpDialog->close();
2685 delete mOtrSmpDialog;
2686 }
2687 mOtrSmpDialog = new OtrFloaterSmpDialog(
2688 this, mSessionUUID, mOtherParticipantUUID,
2689 my_fingerprint, other_fingerprint);
2690 if (mOtrSmpDialog) mOtrSmpDialog->show();
2691 else
2692 {
2693 llwarns << "$PLOTR$ couldn't new OtrFloaterSmpDialog" << llendl;
2694 }
2695}
2696
2697void LLFloaterIMPanel::startSmpDialogQA(
2698 LLUUID session_id, LLUUID other_id, std::string question, OtrlTLV *tlv)
2699{
2700 if (mOtrSmpDialog)
2701 {
2702 mOtrSmpDialog->close();
2703 delete mOtrSmpDialog;
2704 }
2705 mOtrSmpDialog = new OtrFloaterSmpDialog(
2706 this, mSessionUUID, mOtherParticipantUUID, question, tlv);
2707 if (mOtrSmpDialog) mOtrSmpDialog->show();
2708 else
2709 {
2710 llwarns << "$PLOTR$ couldn't new OtrFloaterSmpDialog" << llendl;
2711 }
2712}
2713
2714void LLFloaterIMPanel::startSmpDialogSS(
2715 LLUUID session_id, LLUUID other_id, OtrlTLV *tlv)
2716{
2717 if (mOtrSmpDialog)
2718 {
2719 mOtrSmpDialog->close();
2720 delete mOtrSmpDialog;
2721 }
2722 mOtrSmpDialog = new OtrFloaterSmpDialog(
2723 this, mSessionUUID, mOtherParticipantUUID, tlv);
2724 if (mOtrSmpProgress) mOtrSmpDialog->show();
2725 else
2726 {
2727 llwarns << "$PLOTR$ couldn't new OtrFloaterSmpDialog" << llendl;
2728 }
2729}
2730
2731void LLFloaterIMPanel::endSmpDialog()
2732{
2733 if (!mOtrSmpDialog)
2734 {
2735 llwarns << "$PLOTR$ couldn't find OtrFloaterSmpDialog" << llendl;
2736 }
2737 else
2738 {
2739 delete mOtrSmpDialog;
2740 mOtrSmpDialog = NULL;
2741 }
2742}
2743
2744void LLFloaterIMPanel::startSmpProgress(
2745 LLUUID session_id, LLUUID other_id,
2746 std::string a_question, std::string a_secret_answer, bool is_reply)
2747{
2748 if (mOtrSmpProgress)
2749 {
2750 mOtrSmpProgress->close();
2751 delete mOtrSmpProgress;
2752 }
2753 mOtrSmpProgress =
2754 new OtrFloaterSmpProgress(this, mSessionUUID, mOtherParticipantUUID,
2755 a_question, a_secret_answer, is_reply);
2756 if (mOtrSmpProgress) mOtrSmpProgress->show();
2757 else
2758 {
2759 llwarns << "$PLOTR$ couldn't new OtrFloaterSmpProgress" << llendl;
2760 }
2761}
2762
2763void LLFloaterIMPanel::startSmpProgress(
2764 LLUUID session_id, LLUUID other_id,
2765 std::string a_secret, bool is_reply)
2766{
2767 if (mOtrSmpProgress)
2768 {
2769 mOtrSmpProgress->close();
2770 delete mOtrSmpProgress;
2771 }
2772 mOtrSmpProgress =
2773 new OtrFloaterSmpProgress(this, mSessionUUID, mOtherParticipantUUID,
2774 a_secret, is_reply);
2775 if (mOtrSmpProgress) mOtrSmpProgress->show();
2776 else
2777 {
2778 llwarns << "$PLOTR$ couldn't new OtrFloaterSmpProgress" << llendl;
2779 }
2780}
2781
2782void LLFloaterIMPanel::endSmpProgress()
2783{
2784 if (!mOtrSmpProgress)
2785 {
2786 llwarns << "$PLOTR$ couldn't find OtrFloaterSmpProgress" << llendl;
2787 }
2788 else
2789 {
2790 delete mOtrSmpProgress;
2791 mOtrSmpProgress = NULL;
2792 }
2793}
2794
2795void LLFloaterIMPanel::handleOtrTlvs(OtrlTLV *tlvs)
2796{
2797 ConnContext *context = getOtrContext();
2798 if (! context)
2799 {
2800 llwarns << "$PLOTR$ Can't find otr context" << llendl;
2801 return;
2802 }
2803 if (! context->smstate)
2804 {
2805 llwarns << "$PLOTR$ OTR context doesn't have smstate" << llendl;
2806 return;
2807 }
2808 if (context->smstate->sm_prog_state == OTRL_SMP_PROG_CHEATED)
2809 {
2810 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_errored");
2811 context->smstate->nextExpected = OTRL_SMP_EXPECT1;
2812 context->smstate->sm_prog_state = OTRL_SMP_PROG_OK;
2813 return;
2814 }
2815 NextExpectedSMP nextMsg = context->smstate->nextExpected;
2816 OtrlTLV *tlv = NULL;
2817 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1Q);
2818 if (tlv)
2819 {
2820 if (nextMsg != OTRL_SMP_EXPECT1)
2821 {
2822 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_errored");
2823 return;
2824 }
2825 // Start a challenge SMP dialog
2826 char *question = (char *)tlv->data;
2827 char *eoq = (char *)memchr(question, '\0', tlv->len);
2828 if (!eoq)
2829 {
2830 llwarns << "$PLOTR$ bad format in OTRL_TLV_SMP1Q, no end to question." << llendl;
2831 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_errored");
2832 return;
2833 }
2834 startSmpDialogQA(mSessionUUID, mOtherParticipantUUID, question, tlv);
2835 if (mOtrSmpProgress) mOtrSmpProgress->setPercent(25);
2836 return;
2837 }
2838 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
2839 if (tlv)
2840 {
2841 if (nextMsg != OTRL_SMP_EXPECT1)
2842 {
2843 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_errored");
2844 return;
2845 }
2846 // Start a challenge SMP dialog
2847 startSmpDialogSS(mSessionUUID, mOtherParticipantUUID, tlv);
2848 if (mOtrSmpProgress) mOtrSmpProgress->setPercent(25);
2849 return;
2850 }
2851 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
2852 if (tlv)
2853 {
2854 if (nextMsg != OTRL_SMP_EXPECT2)
2855 {
2856 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_errored");
2857 return;
2858 }
2859 else
2860 {
2861 // If we received TLV2, we will send TLV3 and expect TLV4
2862 context->smstate->nextExpected = OTRL_SMP_EXPECT4;
2863 if (mOtrSmpProgress) mOtrSmpProgress->setPercent(75);
2864 }
2865 }
2866 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
2867 if (tlv)
2868 {
2869 if (nextMsg != OTRL_SMP_EXPECT3)
2870 {
2871 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_errored");
2872 return;
2873 }
2874 else
2875 {
2876 // If we received TLV3, we will send TLV4
2877 // We will not expect more messages, so prepare for next SMP
2878 context->smstate->nextExpected = OTRL_SMP_EXPECT1;
2879 // Report result to user
2880 if (context->smstate->sm_prog_state == OTRL_SMP_PROG_SUCCEEDED)
2881 {
2882 if (context->active_fingerprint &&
2883 context->active_fingerprint->trust &&
2884 *(context->active_fingerprint->trust))
2885 {
2886 // they authed me OK, and I already authed them in the past
2887 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_ok");
2888 }
2889 else
2890 {
2891 // they authed me OK, but I haven't authed them yet
2892 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_ok_name_next");
2893 }
2894 }
2895 else
2896 {
2897 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_failed");
2898 }
2899 }
2900 }
2901 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
2902 if (tlv)
2903 {
2904 if (nextMsg != OTRL_SMP_EXPECT4)
2905 {
2906 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_errored");
2907 return;
2908 }
2909 else {
2910 // We will not expect more messages, so prepare for next SMP
2911 context->smstate->nextExpected = OTRL_SMP_EXPECT1;
2912 // Report result to user
2913 if (context->active_fingerprint &&
2914 context->active_fingerprint->trust &&
2915 *(context->active_fingerprint->trust))
2916 {
2917 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_ok");
2918 }
2919 else
2920 {
2921 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_failed");
2922 }
2923 }
2924 }
2925 tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
2926 if (tlv)
2927 {
2928 // The message we are waiting for will not arrive, so reset
2929 // and prepare for the next SMP
2930 context->smstate->nextExpected = OTRL_SMP_EXPECT1;
2931 if (mOtrSmpProgress) mOtrSmpProgress->setFinalStatus("otr_smp_prog_auth_aborted");
2932 }
2933}
2934#endif // USE_OTR // [/$PLOTR$]
2935
2122void LLFloaterIMPanel::sendMsg() 2936void LLFloaterIMPanel::sendMsg()
2123{ 2937{
2124 if (!gAgent.isGodlike() 2938 if (!gAgent.isGodlike()
@@ -2211,11 +3025,137 @@ void LLFloaterIMPanel::sendMsg()
2211 3025
2212 if ( mSessionInitialized ) 3026 if ( mSessionInitialized )
2213 { 3027 {
3028#if USE_OTR // [$PLOTR$]
3029 const LLRelationship* info = NULL;
3030 info = LLAvatarTracker::instance().getBuddyInfo(mOtherParticipantUUID);
3031 ConnContext *context = getOtrContext(1);
3032 if (info && (!info->isOnline()) && context &&
3033 ( (OTRL_MSGSTATE_ENCRYPTED == context->msgstate)
3034 || (OTRL_MSGSTATE_FINISHED == context->msgstate)))
3035 {
3036 // we can't continue this encrypted session but we
3037 // can't let the user accidentally send unencrypted
3038 if (OTRL_MSGSTATE_ENCRYPTED == context->msgstate)
3039 pretendTheyOtrStop();
3040 otrLogMessageGetstringName("otr_err_offline_send");
3041 return; // leave the unsent message in the edit box
3042 }
3043
3044 gcry_error_t err = 0;
3045 char *newmessage = NULL;
3046 char my_uuid[UUID_STR_SIZE];
3047 char their_uuid[UUID_STR_SIZE];
3048 gAgent.getID().toString(&(my_uuid[0]));
3049 mOtherParticipantUUID.toString(&(their_uuid[0]));
3050
3051 bool was_finished = false;
3052 if (gOTR && context && (context->msgstate == OTRL_MSGSTATE_FINISHED))
3053 {
3054 was_finished = true;
3055 }
3056 else if (gOTR && (IM_NOTHING_SPECIAL == mDialog))
3057 {
3058 // only try OTR for 1 on 1 IM's
3059 err = otrl_message_sending(
3060 gOTR->get_userstate(),
3061 gOTR->get_uistate(),
3062 &mSessionUUID,
3063 my_uuid,
3064 gOTR->get_protocolid(),
3065 their_uuid,
3066 &(utf8_text[0]), NULL, &newmessage,
3067 NULL, NULL);
3068 }
3069 context = getOtrContext();
3070 if (err)
3071 {
3072 otrLogMessageGetstring("otr_err_failed_sending");
3073 return; // leave the unsent message in the edit box
3074 }
3075 if (was_finished)
3076 {
3077 llinfos << "$PLOTR$ OTR tried to send into finished conv, not sending message!" << llendl;
3078 //otrLogMessageGetstringName("otr_err_send_in_finished"); //Don't error and tell the user to restart, just restart instead!
3079 doOtrStart();
3080 return; // leave the unsent message in the edit box
3081 }
3082 OtrlMessageType msgtype = OTRL_MSGTYPE_NOTOTR;
3083 if (newmessage) msgtype = otrl_proto_message_type(newmessage);
3084 if (newmessage && (OTRL_MSGTYPE_TAGGEDPLAINTEXT == msgtype))
3085 {
3086 // OTR just added the whitespace tag.
3087 otrl_message_free(newmessage); // don't send the message with whitespace tag
3088 err = otrl_message_sending(
3089 gOTR->get_userstate(),
3090 gOTR->get_uistate(),
3091 &mSessionUUID,
3092 my_uuid,
3093 gOTR->get_protocolid(),
3094 their_uuid,
3095 "typing", NULL, &newmessage,
3096 NULL, NULL);
3097 if (!newmessage)
3098 {
3099 llwarns << "$PLOTR$ shouldn't happen, OTR should keep adding whitespace tags till we get a reply from them." << llendl;
3100 }
3101 else
3102 {
3103 // deliver a whitespace tagged "typing" in a IM_TYPING_STOP packet
3104 std::string my_name;
3105 gAgent.buildFullname(my_name);
3106 const LLRelationship* info = NULL;
3107 info = LLAvatarTracker::instance().getBuddyInfo(mOtherParticipantUUID);
3108 U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE;
3109 pack_instant_message(
3110 gMessageSystem,
3111 gAgent.getID(),
3112 FALSE,
3113 gAgent.getSessionID(),
3114 mOtherParticipantUUID,
3115 my_name,
3116 newmessage,
3117 offline,
3118 IM_TYPING_STOP,
3119 mSessionUUID);
3120 gAgent.sendReliableMessage();
3121 otrl_message_free(newmessage);
3122 newmessage = NULL;
3123 }
3124 }
3125 if (newmessage)
3126 {
3127 // OTR encrypted the message
3128 if (! context)
3129 {
3130 llwarns << "$PLOTR$ can't find context, not sending message." << llendl;
3131 otrLogMessageGetstring("otr_err_failed_sending");
3132 return; // leave the unsent message in the edit box
3133 }
3134
3135 {
3136 // Handle fragmentation of the message
3137 char *extrafragment = NULL;
3138 err = otrl_message_fragment_and_send(
3139 gOTR->get_uistate(),
3140 &mSessionUUID,
3141 context,
3142 newmessage,
3143 OTRL_FRAGMENT_SEND_ALL,
3144 &extrafragment);
3145 }
3146 if (newmessage) otrl_message_free(newmessage);
3147 showOtrStatus();
3148 }
3149 else
3150 { // OTR didn't encrypt, or we didn't try cause it's not 1:1 IM
3151#endif // USE_OTR // [/$PLOTR$]
2214 deliver_message(utf8_text, 3152 deliver_message(utf8_text,
2215 mSessionUUID, 3153 mSessionUUID,
2216 mOtherParticipantUUID, 3154 mOtherParticipantUUID,
2217 mDialog); 3155 mDialog);
2218 3156#if USE_OTR // [$PLOTR$]
3157 }
3158#endif // USE_OTR // [/$PLOTR$]
2219 // local echo 3159 // local echo
2220 if((mDialog == IM_NOTHING_SPECIAL) && 3160 if((mDialog == IM_NOTHING_SPECIAL) &&
2221 (mOtherParticipantUUID.notNull())) 3161 (mOtherParticipantUUID.notNull()))
@@ -2242,16 +3182,31 @@ void LLFloaterIMPanel::sendMsg()
2242 std::string prefix = utf8_text.substr(0, 4); 3182 std::string prefix = utf8_text.substr(0, 4);
2243 if (prefix == "/me " || prefix == "/me'") 3183 if (prefix == "/me " || prefix == "/me'")
2244 { 3184 {
3185#if USE_OTR // [$PLOTR$]
3186 if (isEncrypted())
3187 utf8_text.replace(0,3,"\xe2\x80\xa7");
3188 else
3189#endif // USE_OTR // [/$PLOTR$]
2245 utf8_text.replace(0,3,""); 3190 utf8_text.replace(0,3,"");
2246 } 3191 }
2247 else 3192 else
2248 { 3193 {
3194#if USE_OTR // [$PLOTR$]
3195 if (isEncrypted())
3196 history_echo += "\xe2\x80\xa7: ";
3197 else
3198#endif // USE_OTR // [/$PLOTR$]
2249 history_echo += ": "; 3199 history_echo += ": ";
2250 } 3200 }
2251 history_echo += utf8_text; 3201 history_echo += utf8_text;
2252 3202
2253 BOOL other_was_typing = mOtherTyping; 3203 BOOL other_was_typing = mOtherTyping;
2254 3204
3205#if USE_OTR // [$PLOTR$]
3206 if (isEncrypted())
3207 addHistoryLine(history_echo, gSavedSettings.getColor("IMEncryptedChatColor"), true, gAgent.getID());
3208 else
3209#endif // USE_OTR // [/$PLOTR$]
2255 addHistoryLine(history_echo, gSavedSettings.getColor("IMChatColor"), true, gAgent.getID()); 3210 addHistoryLine(history_echo, gSavedSettings.getColor("IMChatColor"), true, gAgent.getID());
2256 3211
2257 if (other_was_typing) 3212 if (other_was_typing)
@@ -2482,7 +3437,27 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string
2482 //self->addHistoryLine(line, LLColor4::grey, FALSE); 3437 //self->addHistoryLine(line, LLColor4::grey, FALSE);
2483 self->mHistoryEditor->appendColoredText(message, false, true, LLColor4::grey); 3438 self->mHistoryEditor->appendColoredText(message, false, true, LLColor4::grey);
2484} 3439}
2485 3440#if 0
3441// user is known to be offline when we receive this
3442void LLFloaterIMPanel::setOffline()
3443{
3444 if(!gAgent.isGodlike())
3445 {
3446 childSetEnabled("profile_tele_btn", false);
3447 }
3448#if USE_OTR // [$PLOTR$]
3449 llinfos << "$PLOTR$ friend went offline" << llendl;
3450 if (gOTR)
3451 {
3452 ConnContext *context = getOtrContext();
3453 if (context && (context->msgstate == OTRL_MSGSTATE_ENCRYPTED))
3454 {
3455 pretendTheyOtrStop();
3456 }
3457 }
3458#endif // USE_OTR // [/$PLOTR$]
3459}
3460#endif // 0
2486void LLFloaterIMPanel::showSessionStartError( 3461void LLFloaterIMPanel::showSessionStartError(
2487 const std::string& error_string) 3462 const std::string& error_string)
2488{ 3463{
@@ -2568,3 +3543,14 @@ bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const
2568} 3543}
2569 3544
2570 3545
3546#if USE_OTR // [$PLOTR$]
3547bool LLFloaterIMPanel::isEncrypted()
3548{
3549 if (gOTR)
3550 {
3551 ConnContext *context = getOtrContext();
3552 if (context && (context->msgstate == OTRL_MSGSTATE_ENCRYPTED)) return true;
3553 }
3554 return false;
3555}
3556#endif // USE_OTR // [/$PLOTR$]