2using System.Collections.Generic;
3using System.Threading.Tasks;
5using System.Windows.Controls;
6using System.Windows.Media;
7using System.Windows.Input;
26 private readonly Dictionary<string, OccupantNode> occupantByNick =
new Dictionary<string, OccupantNode>();
27 private readonly
string roomId;
28 private readonly
string domain;
29 private readonly
string name;
30 private string nickName;
31 private string password;
33 private bool entering =
false;
35 public RoomNode(
TreeNode Parent,
string RoomId,
string Domain,
string NickName,
string Password,
string Name,
bool Entered)
41 this.nickName = NickName;
42 this.password = Password;
43 this.entered = Entered;
48 public override string Header
52 if (!
string.IsNullOrEmpty(this.name))
55 if (this.domain == (this.Parent as
MucService)?.JID)
62 public override string Key => this.Jid;
63 public string RoomId => this.roomId;
64 public string Domain => this.domain;
65 public string NickName => this.nickName;
66 public string Password => this.password;
67 public string Jid => this.roomId +
"@" + this.domain;
68 public bool Entered => this.entered;
69 public bool Entering => this.entering;
71 public int NrOccupants
75 lock (this.occupantByNick)
77 return this.occupantByNick.Count;
82 private void SetParameters()
84 List<Parameter> Parameters =
new List<Parameter>()
90 if (!
string.IsNullOrEmpty(this.name))
93 if (!
string.IsNullOrEmpty(this.nickName))
94 Parameters.Add(
new StringParameter(
"NickName",
"Nick-Name", this.nickName));
96 this.children =
new SortedDictionary<string, TreeNode>()
98 {
string.Empty,
new Loading(
this) }
104 public override string ToolTip => this.name;
105 public override bool CanRecycle =>
true;
109 this.entered =
false;
110 return Task.CompletedTask;
113 public override string TypeName =>
"Multi-User Chat Room";
115 public override ImageSource ImageResource
119 if (this.domain == (this.Parent as
MucService)?.JID)
136 public override void Write(XmlWriter Output)
147 while (!(Loop is
null))
159 private bool loadingChildren =
false;
165 return this.Service?.MucClient;
169 public override bool CanAddChildren =>
true;
170 public override bool CanEdit =>
true;
171 public override bool CanDelete =>
true;
172 public override bool CustomDeleteQuestion =>
true;
178 if (!this.loadingChildren && !this.IsLoaded)
180 Mouse.OverrideCursor = Cursors.Wait;
181 this.loadingChildren =
true;
183 if (!await this.AssertEntered(
true))
185 this.loadingChildren =
false;
190 this.MucClient?.
GetOccupants(this.roomId, this.domain,
null,
null, (Sender, e) =>
192 this.loadingChildren =
false;
195 this.Service.NodesRemoved(this.children.Values,
this);
199 SortedDictionary<string, TreeNode> Children = new SortedDictionary<string, TreeNode>();
201 lock (this.occupantByNick)
203 foreach (KeyValuePair<string, OccupantNode> P in this.occupantByNick)
204 Children[P.Key] = P.Value;
209 Children[Occupant.Jid] = this.CreateOccupantNode(Occupant.RoomId, Occupant.Domain, Occupant.NickName,
210 Occupant.Affiliation, Occupant.Role, Occupant.Jid);
213 this.children =
new SortedDictionary<string, TreeNode>(
Children);
215 this.Service.NodesAdded(
Children.Values,
this);
218 MainWindow.ShowStatus(
string.IsNullOrEmpty(e.ErrorText) ?
"Unable to get occupants." : e.ErrorText);
220 return Task.CompletedTask;
229 this.loadingChildren =
false;
236 lock (this.occupantByNick)
238 if (!this.occupantByNick.TryGetValue(NickName, out OccupantNode Node))
240 Node =
new OccupantNode(
this, RoomId, Domain, NickName,
Affiliation,
Role, Jid);
242 lock (this.occupantByNick)
243 this.occupantByNick[NickName] = Node;
252 base.UnloadChildren();
256 if (!(this.children is
null))
257 this.Service?.NodesRemoved(this.children.Values,
this);
259 this.children =
new SortedDictionary<string, TreeNode>()
261 {
string.Empty,
new Loading(
this) }
268 internal async
void EnterIfNotAlready(
bool ForwardPresence)
272 await this.AssertEntered(ForwardPresence);
280 private async Task<bool> AssertEntered(
bool ForwardPresence)
282 if (!this.entered && !this.entering)
284 this.entering =
true;
291 Mouse.OverrideCursor = Cursors.Wait;
293 if (
string.IsNullOrEmpty(this.nickName))
303 this.nickName = Id.
Name;
311 if (
string.IsNullOrEmpty(this.nickName))
314 e = await this.MucClient.EnterRoomAsync(this.roomId, this.domain, this.nickName, this.password);
316 while (!(e?.Ok ??
false))
318 TaskCompletionSource<bool> InputReceived =
new TaskCompletionSource<bool>();
324 Owner = MainWindow.currentInstance
327 Form.NickName.Text = this.nickName;
328 Form.Password.Password = this.password;
334 bool? Result = Form.ShowDialog();
335 InputReceived.TrySetResult(Result.HasValue && Result.Value);
336 return Task.CompletedTask;
339 if (!await InputReceived.Task)
341 this.entered =
false;
345 Mouse.OverrideCursor = Cursors.Wait;
346 e = await this.MucClient.EnterRoomAsync(this.roomId, this.domain, Form.NickName.Text, Form.Password.Password);
353 string Prefix = this.MucClient.Client.BareJID +
"." + this.roomId +
"@" + this.domain;
354 bool Updated =
false;
356 if (this.nickName != Form.NickName.Text)
358 this.nickName = Form.NickName.Text;
363 if (this.password != Form.Password.Password)
365 this.password = Form.Password.Password;
375 await this.Service.MucClient_OccupantPresence(
this, e);
381 this.entering =
false;
388 public override async
void Edit()
392 if (!await this.AssertEntered(
true))
395 DataForm ConfigurationForm = await this.MucClient.GetRoomConfigurationAsync(this.roomId, this.domain, (Sender, e) =>
400 return Task.CompletedTask;
403 MainWindow.currentInstance.ShowDataForm(ConfigurationForm);
415 Owner = MainWindow.currentInstance
418 bool? Result = Form.ShowDialog();
419 if (!Result.HasValue || !Result.Value)
422 await this.MucClient.DestroyRoom(this.roomId, this.domain, Form.Reason.Text, Form.AlternativeRoomJid.Text, (Sender, e) =>
425 base.Delete(Parent, OnDeleted);
427 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ?
"Unable to destroy room." : e.ErrorText);
429 return Task.CompletedTask;
435 this.EnterIfNotAlready(
true);
437 base.SelectionChanged();
440 public override async
void Add()
446 Owner = MainWindow.currentInstance
449 bool? Result = Form.ShowDialog();
450 if (!Result.HasValue || !Result.Value)
453 string BareJid = Form.BareJid.Text.Trim();
454 string Reason = Form.Reason.Text.Trim();
455 bool InvitationSent =
false;
458 if (!(
Item is
null) &&
Item.HasLastPresence &&
Item.LastPresence.IsOnline)
464 await this.MucClient.InviteDirect(this.roomId, this.domain, BareJid, Reason,
string.Empty, this.password);
465 MainWindow.ShowStatus(
"Direct Invitation sent.");
466 InvitationSent =
true;
472 await this.MucClient.Invite(this.roomId, this.domain, Form.BareJid.Text, Form.Reason.Text);
482 public override bool CanChat =>
true;
486 if (Markdown is
null)
487 await this.MucClient.SendGroupChatMessage(this.roomId, this.domain,
Message,
string.Empty, ThreadId);
490 await this.MucClient.SendCustomGroupChatMessage(this.roomId, this.domain, await
XmppContact.MultiFormatMessage(
Message, Markdown),
491 string.Empty, ThreadId);
499 lock (this.occupantByNick)
505 return base.RemoveChild(Node);
512 lock (this.occupantByNick)
514 this.occupantByNick[NickName] = Node;
519 if (this.children is
null)
520 this.children =
new SortedDictionary<string, TreeNode>() { { Node.Key, Node } };
525 this.children[Node.Key] = Node;
531 this.Service?.Account?.View?.NodeAdded(
this, Node);
535 foreach (TreeNode Node2 in Node.Children)
536 this.Service?.Account?.View?.NodeAdded(Node, Node2);
541 return Task.CompletedTask;
552 lock (this.occupantByNick)
554 if (!this.occupantByNick.TryGetValue(NickName, out Result))
558 if (!(Result is
null))
560 bool Changed =
false;
568 if (
Role.HasValue &&
Role != Result.Role)
574 if (!
string.IsNullOrEmpty(Jid) && Jid != Result.Jid)
586 Result = this.AddOccupantNode(this.roomId, this.domain, NickName,
Affiliation,
Role, Jid);
593 base.AddContexMenuItems(ref CurrentGroup, Menu);
598 this.GroupSeparator(ref CurrentGroup,
"MUC", Menu);
600 Menu.Items.Add(
Item =
new MenuItem()
602 Header =
"_Register with room...",
606 Item.Click += this.RegisterWithRoom_Click;
608 Menu.Items.Add(
Item =
new MenuItem()
610 Header =
"Request _voice...",
614 Item.Click += this.RequestPrivileges_Click;
616 Menu.Items.Add(
Item =
new MenuItem()
618 Header =
"Change _Subject...",
622 Item.Click += this.ChangeSubject_Click;
624 Menu.Items.Add(
Item =
new MenuItem()
626 Header =
"Occupant Lists",
630 Item.Items.Add(Item2 =
new MenuItem()
632 Header =
"Owners...",
636 Item2.Click += this.GetOwnersList_Click;
638 Item.Items.Add(Item2 =
new MenuItem()
640 Header =
"Administrators...",
644 Item2.Click += this.GetAdministratorsList_Click;
646 Item.Items.Add(Item2 =
new MenuItem()
648 Header =
"Moderators...",
652 Item2.Click += this.GetModeratorsList_Click;
654 Item.Items.Add(Item2 =
new MenuItem()
656 Header =
"Members...",
660 Item2.Click += this.GetMembersList_Click;
662 Item.Items.Add(Item2 =
new MenuItem()
664 Header =
"Participants...",
668 Item2.Click += this.GetParticipantsList_Click;
670 Item.Items.Add(Item2 =
new MenuItem()
672 Header =
"Visitors...",
676 Item2.Click += this.GetVisitorsList_Click;
678 Item.Items.Add(Item2 =
new MenuItem()
680 Header =
"Outcasts...",
684 Item2.Click += this.GetOutcastsList_Click;
687 private void RegisterWithRoom_Click(
object Sender, RoutedEventArgs e)
689 Mouse.OverrideCursor = Cursors.Wait;
691 this.MucClient.GetRoomRegistrationForm(this.roomId, this.domain, (sender2, e2) =>
697 if (e2.AlreadyRegistered)
699 if (this.nickName != e2.UserName)
701 string Prefix = this.MucClient.Client.BareJID +
"." + this.roomId +
"@" + this.domain;
703 this.nickName = e2.UserName;
704 RuntimeSettings.Set(Prefix +
".Nick", this.nickName);
706 this.EnterIfNotAlready(true);
709 MainWindow.MessageBox(
"You are already registered in the room with nick-name '" + e2.UserName +
"'.",
710 "Information", MessageBoxButton.OK, MessageBoxImage.Information);
714 MainWindow.UpdateGui(async () =>
716 ParameterDialog Dialog = await ParameterDialog.CreateAsync(e2.Form);
724 return Task.CompletedTask;
728 private async
void RequestPrivileges_Click(
object Sender, RoutedEventArgs e)
732 await this.MucClient.RequestVoice(this.roomId, this.domain);
733 MainWindow.SuccessBox(
"Voice privileges requested.");
741 private void ChangeSubject_Click(
object Sender, RoutedEventArgs e)
745 Owner = MainWindow.currentInstance
748 bool? b = Form.ShowDialog();
750 if (b.HasValue && b.Value)
751 this.MucClient.ChangeRoomSubject(this.roomId, this.domain, Form.Subject.Text);
756 this.MucClient.LeaveRoom(this.roomId, this.domain, this.nickName,
null,
null);
757 this.entered =
false;
760 private void GetAdministratorsList_Click(
object Sender, RoutedEventArgs e)
762 this.MucClient.GetAdminList(this.roomId, this.domain, this.OccupantListCallback,
"Administrators");
765 private void GetOwnersList_Click(
object Sender, RoutedEventArgs e)
767 this.MucClient.GetOwnerList(this.roomId, this.domain, this.OccupantListCallback,
"Owners");
770 private void GetModeratorsList_Click(
object Sender, RoutedEventArgs e)
772 this.MucClient.GetModeratorList(this.roomId, this.domain, this.OccupantListCallback,
"Moderators");
775 private void GetMembersList_Click(
object Sender, RoutedEventArgs e)
777 this.MucClient.GetMemberList(this.roomId, this.domain, this.OccupantListCallback,
"Members");
780 private void GetParticipantsList_Click(
object Sender, RoutedEventArgs e)
782 this.MucClient.GetVoiceList(this.roomId, this.domain, this.OccupantListCallback,
"Participants");
785 private void GetVisitorsList_Click(
object Sender, RoutedEventArgs e)
787 this.MucClient.GetOccupants(this.roomId, this.domain,
null,
Role.Visitor,
this.OccupantListCallback,
"Visitors");
790 private void GetOutcastsList_Click(
object Sender, RoutedEventArgs e)
792 this.MucClient.GetBannedOccupants(this.roomId, this.domain, this.OccupantListCallback,
"Outcasts");
801 Owner = MainWindow.currentInstance
806 bool? b = Form.ShowDialog();
807 if (b.HasValue && b.Value)
809 this.MucClient.ConfigureOccupants(this.roomId, this.domain, Form.GetChanges(), (sender2, e2) =>
812 MainWindow.ErrorBox(string.IsNullOrEmpty(e.ErrorText) ?
"Unable to apply changes." : e.ErrorText);
814 return Task.CompletedTask;
818 return Task.CompletedTask;
824 return Task.CompletedTask;
Interaction logic for xaml
Represents a data source in a concentrator.
Represents an occupant in a room hosted by a Multi-User Chat service.
Represents a room hosted by a Multi-User Chat service.
override void AddContexMenuItems(ref string CurrentGroup, ContextMenu Menu)
Adds context sensitive menu items to a context menu.
override async void Edit()
Is called when the user wants to edit a node.
override void Write(XmlWriter Output)
Saves the object to a file.
override async void Add()
Is called when the user wants to add a node to the current node.
override async Task SendChatMessage(string Message, string ThreadId, MarkdownDocument Markdown)
Sends a chat message.
override async void LoadChildren()
Method is called to make sure children are loaded.
override bool RemoveChild(TreeNode Node)
Removes a child node.
override void ViewClosed()
Method called when the view has been closed.
override async Task Delete(TreeNode Parent, EventHandler OnDeleted)
Method called when a node is to be deleted.
override Task Recycle(MainWindow Window)
Is called when the user wants to recycle the node.
override void UnloadChildren()
Method is called to notify children can be unloaded.
override void SelectionChanged()
Method called when selection has been changed.
Abstract base class for tree nodes in the connection view.
TreeNode[] Children
Children of the node. If null, children are not loaded.
virtual DisplayableParameters DisplayableParameters
Gets available displayable parameters.
TreeNode Parent
Parent node. May be null if a root node.
bool IsExpanded
If the node is expanded.
Class representing a normal XMPP account.
Contains a markdown document. This markdown document class supports original markdown,...
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
bool Ok
If the response is an OK result response (true), or an error response (false).
object State
State object passed to the original request.
string ErrorText
Any error specific text.
bool Ok
If the response is an OK result response (true), or an error response (false).
XmppClient Client
XMPP Client. Is null if event raised by a component.
string ErrorText
Any error specific text.
Multi-User Chat room occupant.
Client managing communication with a Multi-User-Chat service. https://xmpp.org/extensions/xep-0045....
Task GetOccupants(string RoomId, string Domain, Affiliation Affiliation, EventHandlerAsync< OccupantListEventArgs > Callback, object State)
Gets a list of occupants having a specific affiliation.
const string NamespaceJabberConference
jabber:x:conference
Event arguments for a occupant list event handlers.
MucOccupant[] Occupants
List of occupants.
Event arguments for user presence events.
Maintains information about an item in the roster.
Contains information about an identity of an entity.
Contains information about an item of an entity.
Event arguments for service discovery responses.
Identity[] Identities
Identities
bool HasFeature(string Feature)
Checks if the remote entity supports a specific feature.
Task< ServiceDiscoveryEventArgs > ServiceDiscoveryAsync(string To)
Performs an asynchronous service discovery request
Static class managing persistent settings.
static async Task< bool > SetAsync(string Key, string Value)
Sets a string-valued setting.
Contains information about a message logged on a node.
Affiliation
Affiliation enumeration
Prefix
SI prefixes. http://physics.nist.gov/cuu/Units/prefixes.html