-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
-\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
- // 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
- System.Windows.Forms.Control sTabControl = e.Tab.Control;\r
-\r
- if (sTabControl is InventoryConsole)\r
- SelectConversation(inventory);\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)\r
- SelectConversation(friends);\r
- else if (sTabControl is VoiceConsole)\r
- SelectConversation(voice);\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 IMTabWindow)\r
- {\r
- IMTabWindow tab = (IMTabWindow)sTabControl;\r
- SelectConversation(tab.TargetName);\r
- }\r
- else if (sTabControl is ObjectsConsole)\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
- System.Windows.Forms.Control sTabControl = e.Tab.Control;\r
-\r
- Mode newConv = null;\r
-\r
- // Create a conversation on first appearance of its tab.\r
- if (sTabControl is InventoryConsole)\r
- newConv = inventory = new Closet(control);\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)\r
- newConv = friends = new Friends(control);\r
- else if (sTabControl is VoiceConsole)\r
- newConv = voice = new Voice(control);\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 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)\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 (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 GroupIMTabWindow ||\r
- sTabControl is IMTabWindow)\r
- RemoveConversation(sTabControl.Name); // TODO wrong name\r
- }\r
-\r
-\r
- internal override void Shutdown()\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
- // 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
- Talker.Say("Trying to start non-existant conversation", Talk.BeepType.Bad );\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
- /// Handle Instant Messages\r
- /// </summary>\r
- /// <param name="im"></param>\r
- /// <param name="simulator"></param>\r
- void OnInstantMessage(object sender, InstantMessageEventArgs e)\r
- {\r
- Conversation.IMSession sess;\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
- }\r
- else if (e.IM.BinaryBucket.Length >= 2)\r
- {\r
- // Ad-hoc friend conference\r
- // TODO this is probably the wrong name\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
- }\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
- }\r
- break;\r
-\r
- case InstantMessageDialog.SessionSend:\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
- 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
+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)
+ {
+ ActivateConversationFromTab(e.Tab);
+ }
+
+ public void ActivateConversationFromTab(RadegastTab Tab)
+ {
+ System.Windows.Forms.Control sTabControl = 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)
+ {
+ CreateConversationFromTab(e.Tab, true);
+ }
+
+ public void CreateConversationFromTab(RadegastTab Tab, bool selectConversation)
+ {
+ System.Windows.Forms.Control sTabControl = 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;
+ }
+ }
+ );
+
+ }
+ }
+}