-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using OpenMetaverse;
-using Radegast;
-using System.Text.RegularExpressions;
-using System.Net;
-using System.Windows.Forms;
-using System.Threading;
-
-namespace RadegastSpeech.Conversation
-{
- /// <summary>
- /// Manages all conversations
- /// </summary>
- internal class Control : AreaControl
- {
- /// <summary>
- /// Conversations correspond to tabbed panels on the main window.
- /// </summary>
- private Dictionary<string, Mode> conversations;
- /// <summary>
- /// Interruptions are short-lived conversations about dialog boxes, etc
- /// </summary>
- private LinkedList<Mode> interruptions;
-
- // The permanent conversations.
- private Conversation.Chat chat;
- private Conversation.Closet inventory;
- private Conversation.Friends friends;
- private Conversation.Voice voice;
- private Conversation.Surroundings surroundings;
- private Mode currentMode;
- private Mode interrupted;
- internal string LoginName;
- private bool firstTime = true;
- private const string CONVGRAMMAR = "conv";
-
- internal Control(PluginControl pc)
- : base(pc)
- {
- // Initialize the index to conversations and the list of pending interruptions.
- interruptions = new LinkedList<Mode>();
- conversations = new Dictionary<string,Mode>();
- }
-
- internal override void Start()
- {
- if (firstTime)
- {
- firstTime = false;
-
- control.listener.CreateGrammar(
- CONVGRAMMAR,
- new string[] { "talk to Max",
- "skip",
- "who is online",
- "open the closet",
- "friends",
- "talk" });
- }
-
- // Automatically handle notifications (blue dialogs)
- Notification.OnNotificationDisplayed +=
- new Notification.NotificationCallback(OnNotificationDisplayed);
-// Notification.OnNotificationClosed +=
-// new Notification.NotificationCallback(OnNotificationClosed);
-
- // Announce connect and disconnect.
- control.instance.Netcom.ClientConnected +=
- new EventHandler<EventArgs>(Network_ClientConnected);
- control.instance.Netcom.ClientDisconnected +=
- new EventHandler<DisconnectedEventArgs>(Network_Disconnected);
-
- control.instance.Netcom.ClientLoginStatus +=
- new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
-
- // Notice arrival in a new sim
- control.instance.Client.Network.SimChanged +=
- new EventHandler<SimChangedEventArgs>(Network_SimChanged);
-
- control.instance.Netcom.ClientLoggingIn +=
- new EventHandler<Radegast.Netcom.OverrideEventArgs>(Netcom_ClientLoggingIn);
- // Watch the coming and going of main window tabs.
- control.instance.TabConsole.OnTabAdded +=
- new TabsConsole.TabCallback(TabConsole_OnTabAdded);
- control.instance.TabConsole.OnTabRemoved +=
- new TabsConsole.TabCallback(TabConsole_OnTabRemoved);
-
- // Notice when the active tab changes on the graphics user interface.
- control.instance.TabConsole.OnTabSelected +=
- new TabsConsole.TabCallback(OnTabChange);
-
- // Handle Instant Messages too
- control.instance.Client.Self.IM +=
- new EventHandler<InstantMessageEventArgs>(OnInstantMessage);
-
- // Watch for global keys
- control.instance.MainForm.KeyUp += new KeyEventHandler(MainForm_KeyUp);
-
- // System messages in chat window
- control.instance.TabConsole.OnChatNotification += new TabsConsole.ChatNotificationCallback(TabConsole_OnChatNotification);
-
- control.listener.ActivateGrammar(CONVGRAMMAR);
-
- }
-
- /// <summary>
- /// Say various notifications that come in the chat
- /// </summary>
- /// <param name="sender">Message sender</param>
- /// <param name="e">Event args</param>
- void TabConsole_OnChatNotification(object sender, ChatNotificationEventArgs e)
- {
- Talker.Say(e.Message);
- }
-
- /// <summary>
- /// Watch for global function keys.
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void MainForm_KeyUp(object sender, KeyEventArgs e)
- {
- // Escape clears the speak-ahead queue.
- if (e.KeyCode == Keys.Escape)
- {
- Talker.Flush();
- Talker.SayMore("Flushed.");
- e.Handled = true;
- }
- }
-
-
- void Netcom_ClientLoggingIn(object sender, Radegast.Netcom.OverrideEventArgs e)
- {
- Talker.SayMore("Logging in. Please wait.");
- }
-
- private void netcom_ClientLoginStatus(
- object sender,
- LoginProgressEventArgs e)
- {
- switch (e.Status)
- {
- case LoginStatus.ConnectingToLogin:
- // Never seems to happen. See Netcom_ClientLoggingIn
- Talker.SayMore("Connecting to login server");
- return;
-
- case LoginStatus.ConnectingToSim:
- Talker.SayMore("Connecting to region");
- return;
-
- case LoginStatus.Success:
- LoginName = control.instance.Netcom.LoginOptions.FullName;
- //Talker.SayMore("Logged in as " + LoginName);
- //if (friends != null)
- // friends.Announce = true;
- return;
-
- case LoginStatus.Failed:
- Talker.Say(e.Message +
- ". Press Enter twice to retry", Talk.BeepType.Bad);
- return;
-
- default:
- return;
- }
- }
-
- /// <summary>
- /// Switch active conversation as tab focus moves.
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void OnTabChange(object sender, TabEventArgs e)
- {
- System.Windows.Forms.Control sTabControl = e.Tab.Control;
-
- if (sTabControl is InventoryConsole)
- SelectConversation(inventory);
- else if (sTabControl is ChatConsole)
- {
- if (chat == null)
- {
- chat = new Chat(control);
- chat.Console = sTabControl;
- AddConversation(chat);
- }
- SelectConversation(chat);
- }
- else if (sTabControl is FriendsConsole)
- SelectConversation(friends);
- else if (sTabControl is VoiceConsole)
- SelectConversation(voice);
- else if (sTabControl is GroupIMTabWindow)
- {
- GroupIMTabWindow tab = (GroupIMTabWindow)sTabControl;
- SelectConversation(
- control.instance.Groups[tab.SessionId].Name);
- }
- else if (sTabControl is ConferenceIMTabWindow)
- {
- ConferenceIMTabWindow tab = (ConferenceIMTabWindow)sTabControl;
- SelectConversation(tab.SessionName);
- }
- else if (sTabControl is IMTabWindow)
- {
- IMTabWindow tab = (IMTabWindow)sTabControl;
- SelectConversation(tab.TargetName);
- }
- else if (sTabControl is ObjectsConsole)
- {
- SelectConversation(surroundings);
- }
-
- }
-
- /// <summary>
- /// Create conversations as tabs are created.
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void TabConsole_OnTabAdded(object sender, TabEventArgs e)
- {
- System.Windows.Forms.Control sTabControl = e.Tab.Control;
-
- Mode newConv = null;
-
- // Create a conversation on first appearance of its tab.
- if (sTabControl is InventoryConsole)
- newConv = inventory = new Closet(control);
- else if (sTabControl is ChatConsole)
- {
- if (chat != null) return;
- newConv = chat = new Chat(control);
- }
- else if (sTabControl is FriendsConsole)
- newConv = friends = new Friends(control);
- else if (sTabControl is VoiceConsole)
- newConv = voice = new Voice(control);
- else if (sTabControl is GroupIMTabWindow)
- {
- GroupIMTabWindow tab = (GroupIMTabWindow)sTabControl;
- AddConversation(new GroupIMSession(control, tab.SessionId));
- return;
- }
- else if (sTabControl is ConferenceIMTabWindow)
- {
- ConferenceIMTabWindow tab = (ConferenceIMTabWindow)sTabControl;
- AddConversation(new ConferenceIMSession(control, tab.SessionId, tab.SessionName));
- return;
- }
- else if (sTabControl is IMTabWindow)
- {
- IMTabWindow tab = (IMTabWindow)sTabControl;
- AddConversation(new SingleIMSession(control, tab.TargetName, tab.TargetId, tab.SessionId));
- return;
- }
- else if (sTabControl is ObjectsConsole)
- {
- surroundings = new Surroundings(control);
- AddConversation(surroundings);
- }
-
- // If a conversation was created, switch to it.
- if (newConv != null)
- {
- AddConversation(newConv);
- // Select CHAT as soon as it is created.
- if (sTabControl is ChatConsole)
- SelectConversation(newConv);
- }
- }
-
- /// <summary>
- /// Quietly close conversations.
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void TabConsole_OnTabRemoved(object sender, TabEventArgs e)
- {
- System.Windows.Forms.Control sTabControl = e.Tab.Control;
- if (sTabControl is InventoryConsole)
- RemoveConversation(inventory.Title);
- else if (sTabControl is ChatConsole)
- RemoveConversation(chat.Title);
- else if (sTabControl is FriendsConsole)
- RemoveConversation(friends.Title);
- else if (sTabControl is VoiceConsole)
- RemoveConversation(voice.Title);
- else if (sTabControl is ConferenceIMTabWindow)
- RemoveConversation(((ConferenceIMTabWindow)e.Tab.Control).SessionName);
- else if (sTabControl is GroupIMTabWindow ||
- sTabControl is IMTabWindow)
- RemoveConversation(sTabControl.Name); // TODO wrong name
- }
-
-
- internal override void Shutdown()
- {
- // Automatically handle notifications (blue dialogs)
- Notification.OnNotificationDisplayed -=
- new Notification.NotificationCallback(OnNotificationDisplayed);
-
- // Announce connect and disconnect.
- control.instance.Netcom.ClientConnected -=
- new EventHandler<EventArgs>(Network_ClientConnected);
- control.instance.Netcom.ClientDisconnected -=
- new EventHandler<DisconnectedEventArgs>(Network_Disconnected);
-
- control.instance.Netcom.ClientLoginStatus -=
- new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);
-
- // Notice arrival in a new sim
- control.instance.Client.Network.SimChanged -=
- new EventHandler<SimChangedEventArgs>(Network_SimChanged);
-
- control.instance.Netcom.ClientLoggingIn -=
- new EventHandler<Radegast.Netcom.OverrideEventArgs>(Netcom_ClientLoggingIn);
- // Watch the coming and going of main window tabs.
- control.instance.TabConsole.OnTabAdded -=
- new TabsConsole.TabCallback(TabConsole_OnTabAdded);
- control.instance.TabConsole.OnTabRemoved -=
- new TabsConsole.TabCallback(TabConsole_OnTabRemoved);
-
- // Notice when the active tab changes on the graphics user interface.
- control.instance.TabConsole.OnTabSelected -=
- new TabsConsole.TabCallback(OnTabChange);
-
- // Handle Instant Messages too
- control.instance.Client.Self.IM +=
- new EventHandler<InstantMessageEventArgs>(OnInstantMessage);
-
- // System notifications in chat
- control.instance.TabConsole.OnChatNotification -= new TabsConsole.ChatNotificationCallback(TabConsole_OnChatNotification);
-
- control.listener.DeactivateGrammar(CONVGRAMMAR);
-
- foreach (Mode m in conversations.Values)
- {
- m.Stop();
- }
- foreach (Mode m in interruptions)
- {
- m.Stop();
- }
- conversations.Clear();
- interruptions.Clear();
- }
-
- void WatchKeys()
- {
- }
-
- internal bool amCurrent(Mode m)
- {
- return (currentMode == m);
- }
-
- /// <summary>
- /// Start an interrupting conversation.
- /// </summary>
- void StartInterruption()
- {
- // Remember what we were talking about.
- if (interrupted == null)
- interrupted = currentMode;
-
- // Visually they stack up, so we take the last one first.
- currentMode = interruptions.Last();
- currentMode.Start();
- }
-
- /// <summary>
- /// Finish an interruption and resume normal conversation
- /// </summary>
- internal void FinishInterruption( Mode m )
- {
- lock (interruptions)
- {
- // Remove the terminating interruption from the list.
- interruptions.Remove(m);
-
- // Let it remove any event hooks, etc
- m.Stop();
-
- // If there are any other interruptions pending, start one.
- // Otherwise resume the interrupted conversation.
- if (interruptions.Count > 0)
- StartInterruption();
- else
- {
- currentMode = interrupted;
- interrupted = null;
- currentMode.Start();
- }
- }
- }
-
- private void Network_ClientConnected(object sender, EventArgs e)
- {
- Talker.Say("You are connected.", Talk.BeepType.Good);
- if (chat == null)
- {
- chat = new Chat(control);
-
- AddConversation(chat);
- SelectConversation(chat);
- }
- }
-
- void Network_SimChanged(object sender, SimChangedEventArgs e)
- {
- Talker.Say("You are now in " +
- control.instance.Client.Network.CurrentSim.Name,
- Talk.BeepType.Good);
- }
-
-
- /// <summary>
- /// Announce reason for disconnect.
- /// </summary>
- /// <param name="reason"></param>
- /// <param name="message"></param>
- private void Network_Disconnected(object sender, DisconnectedEventArgs e)
- {
- switch (e.Reason)
- {
- case NetworkManager.DisconnectType.ClientInitiated:
- Talker.Say("You are disconnected.");
- break;
- case NetworkManager.DisconnectType.SimShutdown:
- Talker.Say("The region you were in has been shut down. You are disconnected.",
- Talk.BeepType.Bad);
- break;
- case NetworkManager.DisconnectType.NetworkTimeout:
- Talker.Say("You have been disconnected by a network timeout.",
- Talk.BeepType.Bad);
- break;
- case NetworkManager.DisconnectType.ServerInitiated:
- Talker.Say("The server has disconnected you. " + e.Message,
- Talk.BeepType.Bad);
- break;
- }
- }
- private void ListFriends()
- {
- List<FriendInfo> onlineFriends =
- control.instance.Client.Friends.FriendList.FindAll(delegate(FriendInfo f) { return f.IsOnline; });
- string list = "";
- foreach (FriendInfo f in onlineFriends)
- {
- list += f.Name + ", ";
- }
- list += "are online.";
- Talker.Say(list);
- }
-
-
- /// <summary>
- /// Check for general commands
- /// </summary>
- /// <param name="message"></param>
- /// <returns>true if command recognized</returns>
- private bool Command(string message)
- {
- switch (message.ToLower())
- {
- case "talk to max":
- AddInterruption(new Max(control));
- break;
- case "who is online":
- ListFriends();
- break;
- case "open the closet":
- control.instance.TabConsole.SelectTab("inventory");
- SelectConversation(inventory);
- break;
- case "friends":
- control.instance.TabConsole.SelectTab("friends");
- SelectConversation(friends);
- break;
- case "skip":
- Talker.Flush();
- Talker.SayMore("Flushed.");
- break;
- case "talk":
- control.instance.TabConsole.SelectTab("chat");
- SelectConversation(chat);
- break;
- case "voice":
- control.instance.TabConsole.SelectTab("voice");
- SelectConversation(voice);
- break;
- default:
- return false;
- }
- return true;
- }
-
- /// <summary>
- /// Dispatch recognized text to appropriate conversation.
- /// </summary>
- /// <param name="message"></param>
- internal void Hear(string message)
- {
- // General commands.
- if (Command(message)) return;
-
- // Let the current conversation handle it.
- if (currentMode != null)
- currentMode.Hear(message);
- }
-
- internal void SelectConversation(Mode c)
- {
- if (c == null)
- {
- Talker.Say("Trying to start non-existant conversation", Talk.BeepType.Bad );
- return;
- }
- // Avoid multiple starts.
- if (currentMode == c) return;
-
- // Let the old conversation deactivate any event hooks, grammars, etc.
- if (currentMode != null)
- currentMode.Stop();
-
- currentMode = c;
- currentMode.Start();
- }
-
- internal void SelectConversation(string name)
- {
- if (conversations.ContainsKey(name))
- {
- SelectConversation(conversations[name]);
- }
- else
- {
- Talker.Say("Can not find conversation " + name, Talk.BeepType.Bad);
- }
- }
-
- /// <summary>
- /// Find an existing conversation by name.
- /// </summary>
- /// <param name="title"></param>
- /// <returns></returns>
- /// <remarks>Used for IM sessions.</remarks>
- internal Mode GetConversation(string title)
- {
- if (conversations.ContainsKey(title))
- return conversations[title];
-
- return null;
- }
-
- /// <summary>
- /// Add a conversation context to those we are tracking.
- /// </summary>
- /// <param name="m"></param>
- internal void AddConversation(Mode m)
- {
- if (!conversations.ContainsKey(m.Title))
- conversations[m.Title] = m;
- }
-
- /// <summary>
- /// Remove the context for a conversation that is no longer visible.
- /// </summary>
- /// <param name="name"></param>
- internal void RemoveConversation(string name)
- {
- bool change = false;
-
- lock (conversations)
- {
- if (conversations.ContainsKey(name))
- {
- Mode doomed = conversations[name];
- if (currentMode == doomed)
- {
- change = true;
- currentMode = chat;
- }
- if (interrupted == doomed)
- interrupted = chat;
-
- conversations.Remove(name);
- if (change)
- SelectConversation(currentMode);
- }
- }
- }
-
- /// <summary>
- /// Take note of a new interruption.
- /// </summary>
- /// <param name="m"></param>
- internal void AddInterruption(Mode m)
- {
- lock (interruptions)
- {
- // Add to the end of the list.
- interruptions.AddLast(m);
-
- // If the list WAS empty, start this.
- if (interruptions.Count == 1)
- StartInterruption();
- }
- }
-
- internal void ChangeFocus(Mode toThis)
- {
- currentMode = toThis;
- if (currentMode != null)
- currentMode.Start();
- }
-
-
- /// <summary>
- /// Event handler for new blue dialog boxes.
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void OnNotificationDisplayed(object sender, NotificationEventArgs e)
- {
- AddInterruption(new Conversation.BlueMenu(control,e));
- }
-
- /// <summary>
- /// Handle Instant Messages
- /// </summary>
- /// <param name="im"></param>
- /// <param name="simulator"></param>
- void OnInstantMessage(object sender, InstantMessageEventArgs e)
- {
- ThreadPool.QueueUserWorkItem(sync =>
- {
- Thread.Sleep(100); // Give tab a chance to show up
- Conversation.IMSession sess = null;
- string groupName;
-
- // All sorts of things come in as a instant messages. For actual messages
- // we need to match them up with an existing Conversation. IM Conversations
- // are keyed by the name of the group or individual involved.
- switch (e.IM.Dialog)
- {
- case InstantMessageDialog.MessageFromAgent:
- if (control.instance.Groups.ContainsKey(e.IM.IMSessionID))
- {
- // Message from a group member
- groupName = control.instance.Groups[e.IM.IMSessionID].Name;
- sess = (IMSession)control.converse.GetConversation(groupName);
- if (sess != null)
- sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);
- else
- Talker.Say(e.IM.FromAgentName + ", " + e.IM.Message);
- }
- else if (e.IM.BinaryBucket.Length >= 2)
- {
- // Ad-hoc friend conference
- sess = (IMSession)control.converse.GetConversation(Utils.BytesToString(e.IM.BinaryBucket));
- if (sess != null)
- sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);
- else
- Talker.Say(e.IM.FromAgentName + ", " + e.IM.Message);
- }
- else if (e.IM.FromAgentName == "Second Life")
- {
- Talker.Say("Second Life says " + e.IM.Message);
- }
- else
- {
- // Message from an individual
- sess = (IMSession)control.converse.GetConversation(e.IM.FromAgentName);
- if (sess != null)
- sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);
- else
- Talker.Say(e.IM.FromAgentName + ", " + e.IM.Message);
- }
- break;
-
- case InstantMessageDialog.SessionSend:
- if (control.instance.Groups.ContainsKey(e.IM.IMSessionID))
- {
- // Message from a group member
- groupName = control.instance.Groups[e.IM.IMSessionID].Name;
- sess = (IMSession)control.converse.GetConversation(groupName);
- }
- else if (e.IM.BinaryBucket.Length >= 2) // ad hoc friends conference
- {
- sess = (IMSession)control.converse.GetConversation(Utils.BytesToString(e.IM.BinaryBucket));
- }
-
- if (sess != null)
- sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);
- break;
-
- case InstantMessageDialog.FriendshipOffered:
- Talker.Say(e.IM.FromAgentName + " is offering friendship.");
- break;
-
- default:
- break;
- }
- }
- );
-
- }
- }
-}
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using OpenMetaverse;\r
+using Radegast;\r
+using System.Text.RegularExpressions;\r
+using System.Net;\r
+using System.Windows.Forms;\r
+#if (COGBOT_LIBOMV || USE_STHREADS)\r
+using ThreadPoolUtil;\r
+using Thread = ThreadPoolUtil.Thread;\r
+using ThreadPool = ThreadPoolUtil.ThreadPool;\r
+using Monitor = ThreadPoolUtil.Monitor;\r
+#endif\r
+using System.Threading;\r
+\r
+namespace RadegastSpeech.Conversation\r
+{\r
+ /// <summary>\r
+ /// Manages all conversations\r
+ /// </summary>\r
+ internal class Control : AreaControl\r
+ {\r
+ /// <summary>\r
+ /// Conversations correspond to tabbed panels on the main window.\r
+ /// </summary>\r
+ private Dictionary<string, Mode> conversations;\r
+ /// <summary>\r
+ /// Interruptions are short-lived conversations about dialog boxes, etc\r
+ /// </summary>\r
+ private LinkedList<Mode> interruptions;\r
+\r
+ // The permanent conversations.\r
+ private Conversation.Chat chat;\r
+ private Conversation.Closet inventory;\r
+ private Conversation.Friends friends;\r
+ private Conversation.Voice voice;\r
+ private Conversation.Surroundings surroundings;\r
+ private Mode currentMode;\r
+ private Mode interrupted;\r
+ internal string LoginName;\r
+ private bool firstTime = true;\r
+ private const string CONVGRAMMAR = "conv";\r
+\r
+ internal Control(PluginControl pc)\r
+ : base(pc)\r
+ {\r
+ // Initialize the index to conversations and the list of pending interruptions.\r
+ interruptions = new LinkedList<Mode>();\r
+ conversations = new Dictionary<string, Mode>();\r
+ }\r
+\r
+ internal override void Start()\r
+ {\r
+ if (firstTime)\r
+ {\r
+ firstTime = false;\r
+\r
+ control.listener.CreateGrammar(\r
+ CONVGRAMMAR,\r
+ new string[] { "talk to Max",\r
+ "skip",\r
+ "who is online",\r
+ "open the closet",\r
+ "friends",\r
+ "talk" });\r
+ }\r
+\r
+ // Automatically handle notifications (blue dialogs)\r
+ Notification.OnNotificationDisplayed +=\r
+ new Notification.NotificationCallback(OnNotificationDisplayed);\r
+ // Notification.OnNotificationClosed +=\r
+ // new Notification.NotificationCallback(OnNotificationClosed);\r
+\r
+ // Announce connect and disconnect.\r
+ control.instance.Netcom.ClientConnected +=\r
+ new EventHandler<EventArgs>(Network_ClientConnected);\r
+ control.instance.Netcom.ClientDisconnected +=\r
+ new EventHandler<DisconnectedEventArgs>(Network_Disconnected);\r
+\r
+ control.instance.Netcom.ClientLoginStatus +=\r
+ new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);\r
+\r
+ // Notice arrival in a new sim\r
+ control.instance.Client.Network.SimChanged +=\r
+ new EventHandler<SimChangedEventArgs>(Network_SimChanged);\r
+\r
+ control.instance.Netcom.ClientLoggingIn +=\r
+ new EventHandler<Radegast.Netcom.OverrideEventArgs>(Netcom_ClientLoggingIn);\r
+ // Watch the coming and going of main window tabs.\r
+ control.instance.TabConsole.OnTabAdded +=\r
+ new TabsConsole.TabCallback(TabConsole_OnTabAdded);\r
+ control.instance.TabConsole.OnTabRemoved +=\r
+ new TabsConsole.TabCallback(TabConsole_OnTabRemoved);\r
+\r
+ // Notice when the active tab changes on the graphics user interface.\r
+ control.instance.TabConsole.OnTabSelected +=\r
+ new TabsConsole.TabCallback(OnTabChange);\r
+\r
+ // Handle Instant Messages too\r
+ control.instance.Client.Self.IM +=\r
+ new EventHandler<InstantMessageEventArgs>(OnInstantMessage);\r
+\r
+ // Outgoing IMs\r
+ control.instance.Netcom.InstantMessageSent += new EventHandler<Radegast.Netcom.InstantMessageSentEventArgs>(Netcom_InstantMessageSent);\r
+\r
+ // Watch for global keys\r
+ control.instance.MainForm.KeyUp += new KeyEventHandler(MainForm_KeyUp);\r
+\r
+ // System messages in chat window\r
+ control.instance.TabConsole.OnChatNotification += new TabsConsole.ChatNotificationCallback(TabConsole_OnChatNotification);\r
+\r
+ control.listener.ActivateGrammar(CONVGRAMMAR);\r
+\r
+ }\r
+\r
+ /// <summary>\r
+ /// Say various notifications that come in the chat\r
+ /// </summary>\r
+ /// <param name="sender">Message sender</param>\r
+ /// <param name="e">Event args</param>\r
+ void TabConsole_OnChatNotification(object sender, ChatNotificationEventArgs e)\r
+ {\r
+ Talker.Say(e.Message);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Watch for global function keys.\r
+ /// </summary>\r
+ /// <param name="sender"></param>\r
+ /// <param name="e"></param>\r
+ void MainForm_KeyUp(object sender, KeyEventArgs e)\r
+ {\r
+ // Escape clears the speak-ahead queue.\r
+ if (e.KeyCode == Keys.Escape)\r
+ {\r
+ Talker.Flush();\r
+ Talker.SayMore("Flushed.");\r
+ e.Handled = true;\r
+ }\r
+ }\r
+\r
+\r
+ void Netcom_ClientLoggingIn(object sender, Radegast.Netcom.OverrideEventArgs e)\r
+ {\r
+ Talker.SayMore("Logging in. Please wait.");\r
+ }\r
+\r
+ private void netcom_ClientLoginStatus(\r
+ object sender,\r
+ LoginProgressEventArgs e)\r
+ {\r
+ switch (e.Status)\r
+ {\r
+ case LoginStatus.ConnectingToLogin:\r
+ // Never seems to happen. See Netcom_ClientLoggingIn\r
+ Talker.SayMore("Connecting to login server");\r
+ return;\r
+\r
+ case LoginStatus.ConnectingToSim:\r
+ Talker.SayMore("Connecting to region");\r
+ return;\r
+\r
+ case LoginStatus.Success:\r
+ LoginName = control.instance.Netcom.LoginOptions.FullName;\r
+ //Talker.SayMore("Logged in as " + LoginName);\r
+ //if (friends != null)\r
+ // friends.Announce = true;\r
+ return;\r
+\r
+ case LoginStatus.Failed:\r
+ Talker.Say(e.Message +\r
+ ". Press Enter twice to retry", Talk.BeepType.Bad);\r
+ return;\r
+\r
+ default:\r
+ return;\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Switch active conversation as tab focus moves.\r
+ /// </summary>\r
+ /// <param name="sender"></param>\r
+ /// <param name="e"></param>\r
+ void OnTabChange(object sender, TabEventArgs e)\r
+ {\r
+ ActivateConversationFromTab(e.Tab);\r
+ }\r
+\r
+ public void ActivateConversationFromTab(RadegastTab Tab)\r
+ {\r
+ System.Windows.Forms.Control sTabControl = Tab.Control;\r
+\r
+ if (sTabControl is InventoryConsole && control.config["enabled_for_inventory"])\r
+ {\r
+ SelectConversation(inventory);\r
+ }\r
+ else if (sTabControl is ChatConsole)\r
+ {\r
+ if (chat == null)\r
+ {\r
+ chat = new Chat(control);\r
+ chat.Console = sTabControl;\r
+ AddConversation(chat);\r
+ }\r
+ SelectConversation(chat);\r
+ }\r
+ else if (sTabControl is FriendsConsole && control.config["enabled_for_friends"])\r
+ {\r
+ SelectConversation(friends);\r
+ }\r
+ else if (sTabControl is VoiceConsole)\r
+ {\r
+ SelectConversation(voice);\r
+ }\r
+ else if (sTabControl is GroupIMTabWindow)\r
+ {\r
+ GroupIMTabWindow tab = (GroupIMTabWindow)sTabControl;\r
+ SelectConversation(\r
+ control.instance.Groups[tab.SessionId].Name);\r
+ }\r
+ else if (sTabControl is ConferenceIMTabWindow)\r
+ {\r
+ ConferenceIMTabWindow tab = (ConferenceIMTabWindow)sTabControl;\r
+ SelectConversation(tab.SessionName);\r
+ }\r
+ else if (sTabControl is IMTabWindow)\r
+ {\r
+ IMTabWindow tab = (IMTabWindow)sTabControl;\r
+ SelectConversation(tab.TargetName);\r
+ }\r
+ else if (sTabControl is ObjectsConsole && control.config["enabled_for_objects"])\r
+ {\r
+ SelectConversation(surroundings);\r
+ }\r
+\r
+ }\r
+\r
+ /// <summary>\r
+ /// Create conversations as tabs are created.\r
+ /// </summary>\r
+ /// <param name="sender"></param>\r
+ /// <param name="e"></param>\r
+ void TabConsole_OnTabAdded(object sender, TabEventArgs e)\r
+ {\r
+ CreateConversationFromTab(e.Tab, true);\r
+ }\r
+\r
+ public void CreateConversationFromTab(RadegastTab Tab, bool selectConversation)\r
+ {\r
+ System.Windows.Forms.Control sTabControl = Tab.Control;\r
+\r
+ Mode newConv = null;\r
+\r
+ // Create a conversation on first appearance of its tab.\r
+ if (sTabControl is InventoryConsole && control.config["enabled_for_inventory"])\r
+ {\r
+ newConv = inventory = new Closet(control);\r
+ }\r
+ else if (sTabControl is ChatConsole)\r
+ {\r
+ if (chat != null) return;\r
+ newConv = chat = new Chat(control);\r
+ }\r
+ else if (sTabControl is FriendsConsole && control.config["enabled_for_friends"])\r
+ {\r
+ newConv = friends = new Friends(control);\r
+ }\r
+ else if (sTabControl is VoiceConsole)\r
+ {\r
+ newConv = voice = new Voice(control);\r
+ }\r
+ else if (sTabControl is GroupIMTabWindow)\r
+ {\r
+ GroupIMTabWindow tab = (GroupIMTabWindow)sTabControl;\r
+ AddConversation(new GroupIMSession(control, tab.SessionId));\r
+ return;\r
+ }\r
+ else if (sTabControl is ConferenceIMTabWindow)\r
+ {\r
+ ConferenceIMTabWindow tab = (ConferenceIMTabWindow)sTabControl;\r
+ AddConversation(new ConferenceIMSession(control, tab.SessionId, tab.SessionName));\r
+ return;\r
+ }\r
+ else if (sTabControl is IMTabWindow)\r
+ {\r
+ IMTabWindow tab = (IMTabWindow)sTabControl;\r
+ AddConversation(new SingleIMSession(control, tab.TargetName, tab.TargetId, tab.SessionId));\r
+ return;\r
+ }\r
+ else if (sTabControl is ObjectsConsole && control.config["enabled_for_objects"])\r
+ {\r
+ surroundings = new Surroundings(control);\r
+ AddConversation(surroundings);\r
+ }\r
+\r
+ // If a conversation was created, switch to it.\r
+ if (newConv != null)\r
+ {\r
+ AddConversation(newConv);\r
+ // Select CHAT as soon as it is created.\r
+ if (selectConversation && sTabControl is ChatConsole)\r
+ SelectConversation(newConv);\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Quietly close conversations.\r
+ /// </summary>\r
+ /// <param name="sender"></param>\r
+ /// <param name="e"></param>\r
+ void TabConsole_OnTabRemoved(object sender, TabEventArgs e)\r
+ {\r
+ System.Windows.Forms.Control sTabControl = e.Tab.Control;\r
+ if (sTabControl is InventoryConsole)\r
+ RemoveConversation(inventory.Title);\r
+ else if (sTabControl is ChatConsole)\r
+ RemoveConversation(chat.Title);\r
+ else if (sTabControl is FriendsConsole)\r
+ RemoveConversation(friends.Title);\r
+ else if (sTabControl is VoiceConsole)\r
+ RemoveConversation(voice.Title);\r
+ else if (sTabControl is ConferenceIMTabWindow)\r
+ RemoveConversation(((ConferenceIMTabWindow)e.Tab.Control).SessionName);\r
+ else if (sTabControl is GroupIMTabWindow ||\r
+ sTabControl is IMTabWindow)\r
+ RemoveConversation(sTabControl.Name); // TODO wrong name\r
+ }\r
+\r
+\r
+ internal override void Shutdown()\r
+ {\r
+ if (chat != null)\r
+ {\r
+ chat.Dispose();\r
+ chat = null;\r
+ }\r
+\r
+ // Automatically handle notifications (blue dialogs)\r
+ Notification.OnNotificationDisplayed -=\r
+ new Notification.NotificationCallback(OnNotificationDisplayed);\r
+\r
+ // Announce connect and disconnect.\r
+ control.instance.Netcom.ClientConnected -=\r
+ new EventHandler<EventArgs>(Network_ClientConnected);\r
+ control.instance.Netcom.ClientDisconnected -=\r
+ new EventHandler<DisconnectedEventArgs>(Network_Disconnected);\r
+\r
+ control.instance.Netcom.ClientLoginStatus -=\r
+ new EventHandler<LoginProgressEventArgs>(netcom_ClientLoginStatus);\r
+\r
+ // Notice arrival in a new sim\r
+ control.instance.Client.Network.SimChanged -=\r
+ new EventHandler<SimChangedEventArgs>(Network_SimChanged);\r
+\r
+ control.instance.Netcom.ClientLoggingIn -=\r
+ new EventHandler<Radegast.Netcom.OverrideEventArgs>(Netcom_ClientLoggingIn);\r
+ // Watch the coming and going of main window tabs.\r
+ control.instance.TabConsole.OnTabAdded -=\r
+ new TabsConsole.TabCallback(TabConsole_OnTabAdded);\r
+ control.instance.TabConsole.OnTabRemoved -=\r
+ new TabsConsole.TabCallback(TabConsole_OnTabRemoved);\r
+\r
+ // Notice when the active tab changes on the graphics user interface.\r
+ control.instance.TabConsole.OnTabSelected -=\r
+ new TabsConsole.TabCallback(OnTabChange);\r
+\r
+ // Handle Instant Messages too\r
+ control.instance.Client.Self.IM -=\r
+ new EventHandler<InstantMessageEventArgs>(OnInstantMessage);\r
+\r
+ // Outgoing IMs\r
+ control.instance.Netcom.InstantMessageSent -= new EventHandler<Radegast.Netcom.InstantMessageSentEventArgs>(Netcom_InstantMessageSent);\r
+\r
+ // System notifications in chat\r
+ control.instance.TabConsole.OnChatNotification -= new TabsConsole.ChatNotificationCallback(TabConsole_OnChatNotification);\r
+\r
+ control.listener.DeactivateGrammar(CONVGRAMMAR);\r
+\r
+ foreach (Mode m in conversations.Values)\r
+ {\r
+ m.Stop();\r
+ }\r
+ foreach (Mode m in interruptions)\r
+ {\r
+ m.Stop();\r
+ }\r
+ conversations.Clear();\r
+ interruptions.Clear();\r
+ }\r
+\r
+ void WatchKeys()\r
+ {\r
+ }\r
+\r
+ internal bool amCurrent(Mode m)\r
+ {\r
+ return (currentMode == m);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Start an interrupting conversation.\r
+ /// </summary>\r
+ void StartInterruption()\r
+ {\r
+ // Remember what we were talking about.\r
+ if (interrupted == null)\r
+ interrupted = currentMode;\r
+\r
+ // Visually they stack up, so we take the last one first.\r
+ currentMode = interruptions.Last();\r
+ currentMode.Start();\r
+ }\r
+\r
+ /// <summary>\r
+ /// Finish an interruption and resume normal conversation\r
+ /// </summary>\r
+ internal void FinishInterruption(Mode m)\r
+ {\r
+ lock (interruptions)\r
+ {\r
+ // Remove the terminating interruption from the list.\r
+ interruptions.Remove(m);\r
+\r
+ // Let it remove any event hooks, etc\r
+ m.Stop();\r
+\r
+ // If there are any other interruptions pending, start one.\r
+ // Otherwise resume the interrupted conversation.\r
+ if (interruptions.Count > 0)\r
+ StartInterruption();\r
+ else\r
+ {\r
+ currentMode = interrupted;\r
+ interrupted = null;\r
+ currentMode.Start();\r
+ }\r
+ }\r
+ }\r
+\r
+ private void Network_ClientConnected(object sender, EventArgs e)\r
+ {\r
+ Talker.Say("You are connected.", Talk.BeepType.Good);\r
+ if (chat == null)\r
+ {\r
+ chat = new Chat(control);\r
+\r
+ AddConversation(chat);\r
+ SelectConversation(chat);\r
+ }\r
+ }\r
+\r
+ void Network_SimChanged(object sender, SimChangedEventArgs e)\r
+ {\r
+ Talker.Say("You are now in " +\r
+ control.instance.Client.Network.CurrentSim.Name,\r
+ Talk.BeepType.Good);\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Announce reason for disconnect.\r
+ /// </summary>\r
+ /// <param name="reason"></param>\r
+ /// <param name="message"></param>\r
+ private void Network_Disconnected(object sender, DisconnectedEventArgs e)\r
+ {\r
+ switch (e.Reason)\r
+ {\r
+ case NetworkManager.DisconnectType.ClientInitiated:\r
+ Talker.Say("You are disconnected.");\r
+ break;\r
+ case NetworkManager.DisconnectType.SimShutdown:\r
+ Talker.Say("The region you were in has been shut down. You are disconnected.",\r
+ Talk.BeepType.Bad);\r
+ break;\r
+ case NetworkManager.DisconnectType.NetworkTimeout:\r
+ Talker.Say("You have been disconnected by a network timeout.",\r
+ Talk.BeepType.Bad);\r
+ break;\r
+ case NetworkManager.DisconnectType.ServerInitiated:\r
+ Talker.Say("The server has disconnected you. " + e.Message,\r
+ Talk.BeepType.Bad);\r
+ break;\r
+ }\r
+ }\r
+ private void ListFriends()\r
+ {\r
+ List<FriendInfo> onlineFriends =\r
+ control.instance.Client.Friends.FriendList.FindAll(delegate(FriendInfo f) { return f.IsOnline; });\r
+ string list = "";\r
+ foreach (FriendInfo f in onlineFriends)\r
+ {\r
+ list += f.Name + ", ";\r
+ }\r
+ list += "are online.";\r
+ Talker.Say(list);\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Check for general commands\r
+ /// </summary>\r
+ /// <param name="message"></param>\r
+ /// <returns>true if command recognized</returns>\r
+ private bool Command(string message)\r
+ {\r
+ switch (message.ToLower())\r
+ {\r
+ case "talk to max":\r
+ AddInterruption(new Max(control));\r
+ break;\r
+ case "who is online":\r
+ ListFriends();\r
+ break;\r
+ case "open the closet":\r
+ control.instance.TabConsole.SelectTab("inventory");\r
+ SelectConversation(inventory);\r
+ break;\r
+ case "friends":\r
+ control.instance.TabConsole.SelectTab("friends");\r
+ SelectConversation(friends);\r
+ break;\r
+ case "skip":\r
+ Talker.Flush();\r
+ Talker.SayMore("Flushed.");\r
+ break;\r
+ case "talk":\r
+ control.instance.TabConsole.SelectTab("chat");\r
+ SelectConversation(chat);\r
+ break;\r
+ case "voice":\r
+ control.instance.TabConsole.SelectTab("voice");\r
+ SelectConversation(voice);\r
+ break;\r
+ default:\r
+ return false;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Dispatch recognized text to appropriate conversation.\r
+ /// </summary>\r
+ /// <param name="message"></param>\r
+ internal void Hear(string message)\r
+ {\r
+ // General commands.\r
+ if (Command(message)) return;\r
+\r
+ // Let the current conversation handle it.\r
+ if (currentMode != null)\r
+ currentMode.Hear(message);\r
+ }\r
+\r
+ internal void SelectConversation(Mode c)\r
+ {\r
+ if (c == null)\r
+ {\r
+ Logger.Log("Trying to start non-existant conversation", Helpers.LogLevel.Warning);\r
+ return;\r
+ }\r
+ // Avoid multiple starts.\r
+ if (currentMode == c) return;\r
+\r
+ // Let the old conversation deactivate any event hooks, grammars, etc.\r
+ if (currentMode != null)\r
+ currentMode.Stop();\r
+\r
+ currentMode = c;\r
+ currentMode.Start();\r
+ }\r
+\r
+ internal void SelectConversation(string name)\r
+ {\r
+ if (conversations.ContainsKey(name))\r
+ {\r
+ SelectConversation(conversations[name]);\r
+ }\r
+ else\r
+ {\r
+ Talker.Say("Can not find conversation " + name, Talk.BeepType.Bad);\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Find an existing conversation by name.\r
+ /// </summary>\r
+ /// <param name="title"></param>\r
+ /// <returns></returns>\r
+ /// <remarks>Used for IM sessions.</remarks>\r
+ internal Mode GetConversation(string title)\r
+ {\r
+ if (conversations.ContainsKey(title))\r
+ return conversations[title];\r
+\r
+ return null;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Add a conversation context to those we are tracking.\r
+ /// </summary>\r
+ /// <param name="m"></param>\r
+ internal void AddConversation(Mode m)\r
+ {\r
+ if (!conversations.ContainsKey(m.Title))\r
+ conversations[m.Title] = m;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Remove the context for a conversation that is no longer visible.\r
+ /// </summary>\r
+ /// <param name="name"></param>\r
+ internal void RemoveConversation(string name)\r
+ {\r
+ bool change = false;\r
+\r
+ lock (conversations)\r
+ {\r
+ if (conversations.ContainsKey(name))\r
+ {\r
+ Mode doomed = conversations[name];\r
+ if (currentMode == doomed)\r
+ {\r
+ change = true;\r
+ currentMode = chat;\r
+ }\r
+ if (interrupted == doomed)\r
+ interrupted = chat;\r
+\r
+ conversations.Remove(name);\r
+ if (change)\r
+ SelectConversation(currentMode);\r
+ }\r
+ }\r
+ }\r
+\r
+ /// <summary>\r
+ /// Take note of a new interruption.\r
+ /// </summary>\r
+ /// <param name="m"></param>\r
+ internal void AddInterruption(Mode m)\r
+ {\r
+ lock (interruptions)\r
+ {\r
+ // Add to the end of the list.\r
+ interruptions.AddLast(m);\r
+\r
+ // If the list WAS empty, start this.\r
+ if (interruptions.Count == 1)\r
+ StartInterruption();\r
+ }\r
+ }\r
+\r
+ internal void ChangeFocus(Mode toThis)\r
+ {\r
+ currentMode = toThis;\r
+ if (currentMode != null)\r
+ currentMode.Start();\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Event handler for new blue dialog boxes.\r
+ /// </summary>\r
+ /// <param name="sender"></param>\r
+ /// <param name="e"></param>\r
+ void OnNotificationDisplayed(object sender, NotificationEventArgs e)\r
+ {\r
+ AddInterruption(new Conversation.BlueMenu(control, e));\r
+ }\r
+\r
+ /// <summary>\r
+ /// Event handler for outgoing IMs\r
+ /// </summary>\r
+ /// <param name="sender"></param>\r
+ /// <param name="e"></param>\r
+ void Netcom_InstantMessageSent(object sender, Radegast.Netcom.InstantMessageSentEventArgs e)\r
+ {\r
+ // Message to an individual\r
+ Conversation.IMSession sess = (IMSession)control.converse.GetConversation(control.instance.Names.Get(e.TargetID, true));\r
+ if (sess != null)\r
+ sess.OnMessage(Client.Self.AgentID, Client.Self.Name, e.Message);\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Handle Instant Messages\r
+ /// </summary>\r
+ /// <param name="im"></param>\r
+ /// <param name="simulator"></param>\r
+ void OnInstantMessage(object sender, InstantMessageEventArgs e)\r
+ {\r
+ WorkPool.QueueUserWorkItem(sync =>\r
+ {\r
+ Thread.Sleep(100); // Give tab a chance to show up\r
+ Conversation.IMSession sess = null;\r
+ string groupName;\r
+\r
+ // All sorts of things come in as a instant messages. For actual messages\r
+ // we need to match them up with an existing Conversation. IM Conversations\r
+ // are keyed by the name of the group or individual involved.\r
+ switch (e.IM.Dialog)\r
+ {\r
+ case InstantMessageDialog.MessageFromAgent:\r
+ if (control.instance.Groups.ContainsKey(e.IM.IMSessionID))\r
+ {\r
+ // Message from a group member\r
+ groupName = control.instance.Groups[e.IM.IMSessionID].Name;\r
+ sess = (IMSession)control.converse.GetConversation(groupName);\r
+ if (sess != null)\r
+ sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);\r
+ else\r
+ Talker.Say(e.IM.FromAgentName + ", " + e.IM.Message);\r
+ }\r
+ else if (e.IM.BinaryBucket.Length >= 2)\r
+ {\r
+ // Ad-hoc friend conference\r
+ sess = (IMSession)control.converse.GetConversation(Utils.BytesToString(e.IM.BinaryBucket));\r
+ if (sess != null)\r
+ sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);\r
+ else\r
+ Talker.Say(e.IM.FromAgentName + ", " + e.IM.Message);\r
+ }\r
+ else if (e.IM.FromAgentName == "Second Life")\r
+ {\r
+ Talker.Say("Second Life says " + e.IM.Message);\r
+ }\r
+ else\r
+ {\r
+ // Message from an individual\r
+ sess = (IMSession)control.converse.GetConversation(e.IM.FromAgentName);\r
+ if (sess != null)\r
+ sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);\r
+ else\r
+ Talker.Say(e.IM.FromAgentName + ", " + e.IM.Message);\r
+ }\r
+ break;\r
+\r
+ case InstantMessageDialog.SessionSend:\r
+ if (control.instance.Groups.ContainsKey(e.IM.IMSessionID))\r
+ {\r
+ // Message from a group member\r
+ groupName = control.instance.Groups[e.IM.IMSessionID].Name;\r
+ sess = (IMSession)control.converse.GetConversation(groupName);\r
+ }\r
+ else if (e.IM.BinaryBucket.Length >= 2) // ad hoc friends conference\r
+ {\r
+ sess = (IMSession)control.converse.GetConversation(Utils.BytesToString(e.IM.BinaryBucket));\r
+ }\r
+\r
+ if (sess != null)\r
+ sess.OnMessage(e.IM.FromAgentID, e.IM.FromAgentName, e.IM.Message);\r
+ break;\r
+\r
+ case InstantMessageDialog.FriendshipOffered:\r
+ Talker.Say(e.IM.FromAgentName + " is offering friendship.");\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ );\r
+\r
+ }\r
+ }\r
+}\r