~ubuntu-branches/ubuntu/trusty/smuxi/trusty-proposed

« back to all changes in this revision

Viewing changes to src/Engine-XMPP/Protocols/Xmpp/XmppProtocolManager.cs

  • Committer: Package Import Robot
  • Author(s): Mirco Bauer
  • Date: 2013-05-25 22:11:31 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20130525221131-nd2mc0kzubuwyx20
Tags: 0.8.11-1
* [22d13d5] Imported Upstream version 0.8.11
* [6d2b95a] Refreshed patches
* [89eb66e] Added ServiceStack libraries to smuxi-engine package
* [848ab10] Enable Campfire engine
* [c6dbdc7] Always build db4o for predictable build result
* [13ec489] Exclude OS X specific libraries from dh_clideps

Show diffs side-by-side

added added

removed removed

Lines of Context:
60
60
#if LOG4NET
61
61
        private static readonly log4net.ILog _Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
62
62
#endif
63
 
        private JabberClient    _JabberClient;
64
 
        private RosterManager   _RosterManager;
65
 
        private ConferenceManager _ConferenceManager;
66
 
        private FrontendManager _FrontendManager;
67
 
        private ChatModel       _NetworkChat;
68
 
        
 
63
        JabberClient JabberClient { get; set; }
 
64
        RosterManager RosterManager { get; set; }
 
65
        ConferenceManager ConferenceManager { get; set; }
 
66
        PresenceManager PresenceManager { get; set; }
 
67
 
 
68
        ChatModel NetworkChat { get; set; }
 
69
        GroupChatModel ContactChat { get; set; }
 
70
        
 
71
        XmppServerModel Server { get; set; }
 
72
        
 
73
        // facebook messed up, this is part of a hack to fix that messup
 
74
        string LastSentMessage { get; set; }
 
75
        bool SupressLocalMessageEcho { get; set; }
 
76
 
69
77
        public override string NetworkID {
70
78
            get {
71
 
                if (!String.IsNullOrEmpty(_JabberClient.NetworkHost)) {
72
 
                    return _JabberClient.NetworkHost;
 
79
                if (!String.IsNullOrEmpty(JabberClient.NetworkHost)) {
 
80
                    return JabberClient.NetworkHost;
73
81
                }
74
 
                if (!String.IsNullOrEmpty(_JabberClient.Server)) {
75
 
                    return _JabberClient.Server;
 
82
                if (!String.IsNullOrEmpty(JabberClient.Server)) {
 
83
                    return JabberClient.Server;
76
84
                }
77
85
                return "XMPP";
78
86
            }
86
94
        
87
95
        public override ChatModel Chat {
88
96
            get {
89
 
                return _NetworkChat;
 
97
                return NetworkChat;
90
98
            }
91
99
        }
92
100
 
94
102
        {
95
103
            Trace.Call(session);
96
104
 
97
 
            _JabberClient = new JabberClient();
98
 
            _JabberClient.Resource = "Smuxi";
99
 
            _JabberClient.AutoLogin = true;
100
 
            _JabberClient.AutoPresence = false;
101
 
            _JabberClient.OnStreamInit += OnStreamInit;
102
 
            _JabberClient.OnMessage += OnMessage;
103
 
            _JabberClient.OnConnect += OnConnect;
104
 
            _JabberClient.OnDisconnect += OnDisconnect;
105
 
            _JabberClient.OnAuthenticate += OnAuthenticate;
106
 
            _JabberClient.OnError += OnError;
107
 
            _JabberClient.OnProtocol += OnProtocol;
108
 
            _JabberClient.OnWriteText += OnWriteText;
109
 
            _JabberClient.OnIQ += OnIQ;
110
 
 
111
 
            _RosterManager = new RosterManager();
112
 
            _RosterManager.Stream = _JabberClient;
113
 
 
114
 
            _ConferenceManager = new ConferenceManager();
115
 
            _ConferenceManager.Stream = _JabberClient;
116
 
            _ConferenceManager.OnJoin += OnJoin;
117
 
            _ConferenceManager.OnLeave += OnLeave;
118
 
            _ConferenceManager.OnParticipantJoin += OnParticipantJoin;
119
 
            _ConferenceManager.OnParticipantLeave += OnParticipantLeave;
 
105
            JabberClient = new JabberClient();
 
106
            JabberClient.Resource = "Smuxi";
 
107
            JabberClient.AutoLogin = true;
 
108
            JabberClient.AutoPresence = false;
 
109
            JabberClient.OnStreamInit += OnStreamInit;
 
110
            JabberClient.OnMessage += OnMessage;
 
111
            JabberClient.OnConnect += OnConnect;
 
112
            JabberClient.OnDisconnect += OnDisconnect;
 
113
            JabberClient.OnAuthenticate += OnAuthenticate;
 
114
            JabberClient.OnError += OnError;
 
115
            JabberClient.OnProtocol += OnProtocol;
 
116
            JabberClient.OnWriteText += OnWriteText;
 
117
            JabberClient.OnIQ += OnIQ;
 
118
 
 
119
            RosterManager = new RosterManager();
 
120
            RosterManager.Stream = JabberClient;
 
121
            RosterManager.OnRosterItem += OnRosterItem;
 
122
 
 
123
            PresenceManager = new PresenceManager();
 
124
            PresenceManager.Stream = JabberClient;
 
125
            JabberClient.OnPresence += OnPresence;
 
126
 
 
127
            ConferenceManager = new ConferenceManager();
 
128
            ConferenceManager.Stream = JabberClient;
 
129
            ConferenceManager.OnJoin += OnJoin;
 
130
            ConferenceManager.OnLeave += OnLeave;
 
131
            ConferenceManager.OnParticipantJoin += OnParticipantJoin;
 
132
            ConferenceManager.OnParticipantLeave += OnParticipantLeave;
120
133
        }
121
134
 
122
135
        public override void Connect(FrontendManager fm, ServerModel server)
129
142
            if (server == null) {
130
143
                throw new ArgumentNullException("server");
131
144
            }
132
 
 
133
 
            _FrontendManager = fm;
 
145
            
 
146
            if (server is XmppServerModel) {
 
147
                Server = (XmppServerModel) server;
 
148
            } else {
 
149
                Server = new XmppServerModel();
 
150
                if (server.ServerID != null) {
 
151
                    Server.Load(Session.UserConfig, server.ServerID);
 
152
                }
 
153
                // HACK: previous line overwrites any passed values with the values from config
 
154
                // thus we have to copy the original values:
 
155
                Server.Hostname = server.Hostname;
 
156
                Server.Network = server.Network;
 
157
                Server.OnConnectCommands = server.OnConnectCommands;
 
158
                Server.OnStartupConnect = server.OnStartupConnect;
 
159
                Server.Password = server.Password;
 
160
                Server.Port = server.Port;
 
161
                Server.Protocol = server.Protocol;
 
162
                Server.ServerID = server.ServerID;
 
163
                Server.UseEncryption = server.UseEncryption;
 
164
                Server.Username = server.Username;
 
165
                Server.ValidateServerCertificate = server.ValidateServerCertificate;
 
166
            }
 
167
            
134
168
            Host = server.Hostname;
135
169
            Port = server.Port;
136
170
 
137
 
            ApplyConfig(Session.UserConfig, server);
 
171
            ApplyConfig(Session.UserConfig, Server);
138
172
 
139
173
            // TODO: use config for single network chat or once per network manager
140
 
            _NetworkChat = Session.CreateChat<ProtocolChatModel>(
 
174
            NetworkChat = Session.CreateChat<ProtocolChatModel>(
141
175
                NetworkID, "Jabber " + Host, this
142
176
            );
143
 
            Session.AddChat(_NetworkChat);
144
 
            Session.SyncChat(_NetworkChat);
145
 
 
146
 
            if (!String.IsNullOrEmpty(_JabberClient.ProxyHost)) {
 
177
            Session.AddChat(NetworkChat);
 
178
            Session.SyncChat(NetworkChat);
 
179
 
 
180
            OpenContactChat();
 
181
 
 
182
            if (!String.IsNullOrEmpty(JabberClient.ProxyHost)) {
147
183
                var builder = CreateMessageBuilder();
148
184
                builder.AppendEventPrefix();
149
185
                builder.AppendText(_("Using proxy: {0}:{1}"),
150
 
                                   _JabberClient.ProxyHost,
151
 
                                   _JabberClient.ProxyPort);
 
186
                                   JabberClient.ProxyHost,
 
187
                                   JabberClient.ProxyPort);
152
188
                Session.AddMessageToChat(Chat, builder.ToMessage());
153
189
            }
154
 
            _JabberClient.Connect();
 
190
            JabberClient.Connect();
155
191
        }
156
192
        
157
193
        public override void Reconnect(FrontendManager fm)
158
194
        {
159
195
            Trace.Call(fm);
160
196
 
161
 
            _JabberClient.Close();
162
 
            _JabberClient.Connect();
 
197
            JabberClient.Close();
 
198
            JabberClient.Connect();
163
199
        }
164
200
        
165
201
        public override void Disconnect(FrontendManager fm)
166
202
        {
167
203
            Trace.Call(fm);
168
204
 
169
 
            _JabberClient.Close(false);
 
205
            JabberClient.Close(false);
170
206
        }
171
207
 
172
208
        public override void Dispose()
175
211
 
176
212
            base.Dispose();
177
213
 
178
 
            _JabberClient.Dispose();
 
214
            JabberClient.Dispose();
179
215
        }
180
216
 
181
217
        public override string ToString()
182
218
        {
183
219
            string result = "Jabber ";
184
 
            if (_JabberClient != null) {
185
 
                result += _JabberClient.Server + ":" + _JabberClient.Port;
 
220
            if (JabberClient != null) {
 
221
                result += JabberClient.Server + ":" + JabberClient.Port;
186
222
            }
187
223
            
188
224
            if (!IsConnected) {
195
231
        {
196
232
            Trace.Call(filter);
197
233
            
198
 
            throw new NotImplementedException();
 
234
            var list = new List<GroupChatModel>();
 
235
            if (ContactChat == null) {
 
236
                list.Add(new GroupChatModel("Contacts", "Contacts", this));
 
237
            }
 
238
            return list;
 
239
        }
 
240
 
 
241
        public void OpenContactChat ()
 
242
        {
 
243
            var chat = Session.GetChat("Contacts", ChatType.Group, this);
 
244
 
 
245
            if (chat != null) return;
 
246
 
 
247
            ContactChat = Session.CreateChat<GroupChatModel>(
 
248
                "Contacts", "Contacts", this
 
249
            );
 
250
            Session.AddChat(ContactChat);
 
251
            Session.SyncChat(ContactChat);
 
252
            foreach(JID jid in PresenceManager) {
 
253
                if (PresenceManager.IsAvailable(jid)) {
 
254
                    lock (ContactChat) {
 
255
                        Session.AddPersonToGroupChat(ContactChat, CreatePerson(jid));
 
256
                    }
 
257
                }
 
258
            }
199
259
        }
200
260
 
201
261
        public override void OpenChat(FrontendManager fm, ChatModel chat)
202
262
        {
203
263
            Trace.Call(fm, chat);
204
 
            
205
 
            throw new NotImplementedException();
 
264
            if (chat.ID == "Contacts") {
 
265
                OpenContactChat();
 
266
                return;
 
267
            }
 
268
            CommandModel cmd = new CommandModel(fm, NetworkChat, chat.ID);
 
269
            switch (chat.ChatType) {
 
270
                case ChatType.Person:
 
271
                    CommandMessageQuery(cmd);
 
272
                    break;
 
273
                case ChatType.Group:
 
274
                    CommandJoin(cmd);
 
275
                    break;
 
276
            }
206
277
        }
207
278
 
208
279
        public override void CloseChat(FrontendManager fm, ChatModel chat)
209
280
        {
210
281
            Trace.Call(fm, chat);
211
282
 
212
 
            if (chat.ChatType == ChatType.Group) {
213
 
                _ConferenceManager.GetRoom(chat.ID+"/"+_JabberClient.User).Leave("Closed");
 
283
            if (chat == ContactChat) {
 
284
                Session.RemoveChat(chat);
 
285
                ContactChat = null;
 
286
            } else if (chat.ChatType == ChatType.Group) {
 
287
                ConferenceManager.GetRoom(chat.ID+"/"+JabberClient.User).Leave("Closed");
214
288
            } else {
215
289
                Session.RemoveChat(chat);
216
290
            }
221
295
        {
222
296
            Trace.Call(status, message);
223
297
 
224
 
            if (!IsConnected || !_JabberClient.IsAuthenticated) {
 
298
            if (!IsConnected || !JabberClient.IsAuthenticated) {
225
299
                return;
226
300
            }
227
301
 
230
304
            switch (status) {
231
305
                case PresenceStatus.Online:
232
306
                    xmppType = PresenceType.available;
 
307
                    JabberClient.Priority = Server.Priorities[status];
233
308
                    break;
234
309
                case PresenceStatus.Away:
235
310
                    xmppType = PresenceType.available;
 
311
                    JabberClient.Priority = Server.Priorities[status];
236
312
                    xmppShow = "away";
237
313
                    break;
238
314
                case PresenceStatus.Offline:
243
319
                return;
244
320
            }
245
321
 
246
 
            _JabberClient.Presence(xmppType.Value, message, xmppShow,
247
 
                                   _JabberClient.Priority);
 
322
            JabberClient.Presence(xmppType.Value, message, xmppShow,
 
323
                                  JabberClient.Priority);
248
324
        }
249
325
 
250
326
        public override bool Command(CommandModel command)
279
355
                            CommandAway(command);
280
356
                            handled = true;
281
357
                            break;
 
358
                        case "roster":
 
359
                            CommandRoster(command);
 
360
                            handled = true;
 
361
                            break;
 
362
                        case "contact":
 
363
                            CommandContact(command);
 
364
                            handled = true;
 
365
                            break;
 
366
                        case "priority":
 
367
                            CommandPriority(command);
 
368
                            handled = true;
 
369
                            break;
282
370
                    }
283
371
                } else {
284
372
                    _Say(command.Chat, command.Data);
307
395
            return handled;
308
396
        }
309
397
 
310
 
        public void CommandHelp(CommandModel cd)
 
398
        public void CommandContact (CommandModel cd)
311
399
        {
312
 
            MessageModel fmsg = new MessageModel();
313
 
            TextMessagePartModel fmsgti;
 
400
            FrontendManager fm = cd.FrontendManager;
 
401
            // todo: allow length of 2 in private chat windows
 
402
            if (cd.DataArray.Length < 3) {
 
403
                NotEnoughParameters(cd);
 
404
                return;
 
405
            }
 
406
            JID jid = cd.DataArray[2];
 
407
            string cmd = cd.DataArray[1];
 
408
            switch (cmd) {
 
409
                case "add":
 
410
                case "subscribe":
 
411
                    // also use GetJidFromNickname(jid) here, so jid is checked for validity
 
412
                    RosterManager.Add(GetJidFromNickname(jid));
 
413
                    break;
 
414
                case "remove":
 
415
                case "rm":
 
416
                case "del":
 
417
                    RosterManager.Remove(GetJidFromNickname(jid));
 
418
                    break;
 
419
                case "accept":
 
420
                case "allow":
 
421
                    RosterManager.Allow(GetJidFromNickname(jid));
 
422
                    break;
 
423
                case "deny":
 
424
                    RosterManager.Deny(GetJidFromNickname(jid));
 
425
                    break;
 
426
                case "rename":
 
427
                    if (cd.DataArray.Length < 4) {
 
428
                        NotEnoughParameters(cd);
 
429
                        return;
 
430
                    }
 
431
                    Item it = RosterManager[GetJidFromNickname(jid)];
 
432
                    it.Nickname = cd.DataArray[3];
 
433
                    RosterManager.Modify(it);
 
434
                    break;
 
435
                default:
 
436
                    var builder = CreateMessageBuilder();
 
437
                    builder.AppendText(_("Invalid Contact command: {0}"), cmd);
 
438
                    fm.AddMessageToChat(cd.Chat, builder.ToMessage());
 
439
                    return;
 
440
            }
 
441
        }
314
442
 
315
 
            fmsgti = new TextMessagePartModel();
 
443
        public void CommandHelp(CommandModel cmd)
 
444
        {
 
445
            var builder = CreateMessageBuilder();
316
446
            // TRANSLATOR: this line is used as a label / category for a
317
447
            // list of commands below
318
 
            fmsgti.Text = "[" + _("XMPP Commands") + "]";
319
 
            fmsgti.Bold = true;
320
 
            fmsg.MessageParts.Add(fmsgti);
321
 
            
322
 
            Session.AddMessageToChat(cd.Chat, fmsg);
323
 
            
 
448
            builder.AppendHeader(_("XMPP Commands"));
 
449
            cmd.FrontendManager.AddMessageToChat(cmd.Chat, builder.ToMessage());
 
450
 
324
451
            string[] help = {
325
452
            "help",
326
453
            "connect xmpp/jabber server port username password [resource]",
327
 
            "msg/query jid message",
 
454
            "msg/query jid/nick message",
328
455
            "say message",
329
 
            "join muc-jid",
 
456
            "join muc-jid [custom-chat-nick]",
330
457
            "part/leave [muc-jid]",
331
 
            "away [away-message]"
 
458
            "away [away-message]",
 
459
            "contact add/remove/accept/deny jid/nick",
 
460
            "contact rename jid/nick newnick"
 
461
            ,"priority away/online/temp priority-value"
332
462
            };
333
463
            
334
 
            foreach (string line in help) { 
335
 
                cd.FrontendManager.AddTextToChat(cd.Chat, "-!- " + line);
 
464
            foreach (string line in help) {
 
465
                builder = CreateMessageBuilder();
 
466
                builder.AppendEventPrefix();
 
467
                builder.AppendText(line);
 
468
                cmd.FrontendManager.AddMessageToChat(cmd.Chat, builder.ToMessage());
336
469
            }
337
470
        }
338
471
        
352
485
                try {
353
486
                    server.Port = Int32.Parse(cd.DataArray[3]);
354
487
                } catch (FormatException) {
355
 
                    fm.AddTextToChat(
356
 
                        cd.Chat,
357
 
                        "-!- " + String.Format(
358
 
                                    _("Invalid port: {0}"),
359
 
                                    cd.DataArray[3]));
 
488
                    var builder = CreateMessageBuilder();
 
489
                    builder.AppendText(_("Invalid port: {0}"), cd.DataArray[3]);
 
490
                    fm.AddMessageToChat(cd.Chat, builder.ToMessage());
360
491
                    return;
361
492
                }
362
493
            } else {
384
515
 
385
516
            Connect(fm, server);
386
517
        }
 
518
 
 
519
        public void CommandPriority(CommandModel command)
 
520
        {
 
521
            if (command.DataArray.Length < 3) {
 
522
                var builder = CreateMessageBuilder();
 
523
                builder.AppendText(_("Priority for Available is: {0}"), Server.Priorities[PresenceStatus.Online]);
 
524
                command.FrontendManager.AddMessageToChat(command.Chat, builder.ToMessage());
 
525
                builder = CreateMessageBuilder();
 
526
                builder.AppendText(_("Priority for Away is: {0}"), Server.Priorities[PresenceStatus.Away]);
 
527
                command.FrontendManager.AddMessageToChat(command.Chat, builder.ToMessage());
 
528
                return;
 
529
            }
 
530
            string subcmd = command.DataArray[1];
 
531
            int prio;
 
532
            if (!int.TryParse(command.DataArray[2], out prio) || prio < -128 || prio > 127) {
 
533
                var builder = CreateMessageBuilder();
 
534
                builder.AppendText(_("Invalid Priority: {0} (valid priorities are between -128 and 127 inclusive)"), command.DataArray[2]);
 
535
                command.FrontendManager.AddMessageToChat(command.Chat, builder.ToMessage());
 
536
                return;
 
537
            }
 
538
            var me = PresenceManager[JabberClient.JID];
 
539
            JabberClient.Priority = prio;
 
540
            bool change_current_prio = false;
 
541
            switch (subcmd) {
 
542
                case "temp":
 
543
                case "temporary":
 
544
                    change_current_prio = true;
 
545
                    // only set priority
 
546
                    break;
 
547
                case "away":
 
548
                    Server.Priorities[PresenceStatus.Away] = prio;
 
549
                    if (me != null) {
 
550
                        change_current_prio = (me.Type == PresenceType.available) && (me.Show == "away");
 
551
                    }
 
552
                    break;
 
553
                case "online":
 
554
                case "available":
 
555
                    Server.Priorities[PresenceStatus.Online] = prio;
 
556
                    if (me != null) {
 
557
                        change_current_prio = (me.Type == PresenceType.available) && string.IsNullOrEmpty(me.Show);
 
558
                    }
 
559
                    break;
 
560
                default:
 
561
                    return;
 
562
            }
 
563
            if (change_current_prio) {
 
564
                // set priority and keep all other presence info
 
565
                JabberClient.Presence(me.Type, me.Status, me.Show, prio);
 
566
            }
 
567
        }
 
568
 
 
569
        private JID GetJidFromNickname(string nickname)
 
570
        {
 
571
            Item it = RosterManager[nickname];
 
572
            if (it != null) {
 
573
                return it.JID;
 
574
            }
 
575
 
 
576
            // arg is not a jid in our rostermanager
 
577
            // find a jid to which the nickname belongs
 
578
            foreach (JID j in RosterManager) {
 
579
                Item item = RosterManager[j];
 
580
                if (item.Nickname != null &&
 
581
                    item.Nickname.Replace(" ", "_") == nickname) {
 
582
                    return item.JID;
 
583
                }
 
584
            }
 
585
            // not found in roster, message directly to jid
 
586
            // TODO: check jid for validity
 
587
            return nickname;
 
588
        }
387
589
        
388
590
        public void CommandMessageQuery(CommandModel cd)
389
591
        {
390
592
            ChatModel chat = null;
391
593
            if (cd.DataArray.Length >= 2) {
392
 
                string nickname = cd.DataArray[1];
393
 
                JID jid = null;
394
 
                foreach (JID j in _RosterManager) {
395
 
                    Item item = _RosterManager[j];
396
 
                    if (item.Nickname != null &&
397
 
                        item.Nickname.Replace(" ", "_") == nickname) {
398
 
                        jid = item.JID;
399
 
                        break;
400
 
                    }
401
 
                }
402
 
                if (jid == null) {
403
 
                    jid = nickname; // TODO check validity
404
 
                }
405
 
 
 
594
                string arg = cd.DataArray[1];
 
595
                JID jid = GetJidFromNickname(arg);
406
596
                chat = GetChat(jid, ChatType.Person);
407
597
                if (chat == null) {
408
 
                    PersonModel person = new PersonModel(jid, nickname,
409
 
                                                         NetworkID, Protocol,
410
 
                                                         this);
411
 
                    chat = Session.CreatePersonChat(person, jid, nickname, this);
 
598
                    PersonModel person = CreatePerson(jid);
 
599
                    chat = Session.CreatePersonChat(person, jid, person.IdentityName, this);
412
600
                    Session.AddChat(chat);
413
601
                    Session.SyncChat(chat);
414
602
                }
432
620
 
433
621
            string jid = cd.DataArray[1];
434
622
            ChatModel chat = GetChat(jid, ChatType.Group);
 
623
            string nickname = JabberClient.User;
 
624
            if (cd.DataArray.Length > 2) {
 
625
                nickname = cd.DataArray[2];
 
626
            }
435
627
            if (chat == null) {
436
 
                _ConferenceManager.GetRoom(jid+"/"+_JabberClient.User).Join();
 
628
                ConferenceManager.GetRoom(jid+"/"+nickname).Join();
437
629
            }
438
630
        }
439
631
 
446
638
                jid = cd.Chat.ID;
447
639
            ChatModel chat = GetChat(jid, ChatType.Group);
448
640
            if (chat != null) {
449
 
                _ConferenceManager.GetRoom(jid+"/"+_JabberClient.User).Leave("Part");
 
641
                ConferenceManager.GetRoom(jid+"/"+JabberClient.User).Leave("Part");
450
642
            }
451
643
        }
452
644
 
459
651
            }
460
652
        }
461
653
 
 
654
        public void CommandRoster(CommandModel cd)
 
655
        {
 
656
            bool full = false;
 
657
            if (cd.Parameter == "full") {
 
658
                full = true;
 
659
            }
 
660
 
 
661
            MessageBuilder builder = CreateMessageBuilder();
 
662
            builder.AppendHeader("Roster");
 
663
            cd.FrontendManager.AddMessageToChat(cd.Chat, builder.ToMessage());
 
664
 
 
665
            foreach (JID j in RosterManager) {
 
666
                string status = "+";
 
667
                if (!PresenceManager.IsAvailable(j)) {
 
668
                    if (!full) continue;
 
669
                    status = "-";
 
670
                }
 
671
                string nick = RosterManager[j].Nickname;
 
672
                string mesg = "";
 
673
                Presence item = PresenceManager[j];
 
674
                if (item != null) {
 
675
                    if (item.Show != null && item.Show.Length != 0) {
 
676
                        status = item.Show;
 
677
                    }
 
678
                    mesg = item.Status;
 
679
                }
 
680
                builder = CreateMessageBuilder();
 
681
                builder.AppendText("{0}\t{1}\t({2}): {3}", status, nick, j, mesg);
 
682
                cd.FrontendManager.AddMessageToChat(cd.Chat, builder.ToMessage());
 
683
            }
 
684
        }
 
685
 
462
686
        public void CommandSay(CommandModel cd)
463
687
        {
464
688
            _Say(cd.Chat, cd.Parameter);
474
698
            if (!chat.IsEnabled) {
475
699
                return;
476
700
            }
 
701
            if (chat == ContactChat) {
 
702
                return;
 
703
            }
477
704
            
478
705
            if (send) {
479
706
                string target = chat.ID;
480
707
                if (chat.ChatType == ChatType.Person) {
481
 
                    _JabberClient.Message(target, text);
 
708
                    JabberClient.Message(target, text);
482
709
                } else if (chat.ChatType == ChatType.Group) {
483
 
                    var room = _ConferenceManager.GetRoom(
 
710
                    var room = ConferenceManager.GetRoom(
484
711
                        String.Format(
485
712
                            "{0}/{1}",
486
 
                            target, _JabberClient.User
 
713
                            target, JabberClient.User
487
714
                        )
488
715
                    );
489
716
                    room.PublicMessage(text);
490
717
                    return; // don't show now. the message will be echoed back if it's sent successfully
491
718
                }
 
719
                if (SupressLocalMessageEcho) {
 
720
                    // don't show, facebook is bugging again
 
721
                    return;
 
722
                }
 
723
                LastSentMessage = text;
492
724
            }
493
725
 
494
 
            MessageModel msg = new MessageModel();
495
 
            TextMessagePartModel msgPart;
496
 
            
497
 
            msgPart = new TextMessagePartModel();
498
 
            msgPart.Text = "<";
499
 
            msg.MessageParts.Add(msgPart);
500
 
            
501
 
            msgPart = new TextMessagePartModel();
502
 
            msgPart.Text = _JabberClient.User;
503
 
            //msgPart.ForegroundColor = IrcTextColor.Blue;
504
 
            msgPart.ForegroundColor = new TextColor(0x0000FF);
505
 
            msg.MessageParts.Add(msgPart);
506
 
            
507
 
            msgPart = new TextMessagePartModel();
508
 
            msgPart.Text = "> ";
509
 
            msg.MessageParts.Add(msgPart);
510
 
                
511
 
            msgPart = new TextMessagePartModel();
512
 
            msgPart.Text = text;
513
 
            msg.MessageParts.Add(msgPart);
514
 
            
515
 
            this.Session.AddMessageToChat(chat, msg);
 
726
            var builder = CreateMessageBuilder();
 
727
            builder.AppendSenderPrefix(Me);
 
728
            builder.AppendMessage(text);
 
729
            Session.AddMessageToChat(chat, builder.ToMessage());
516
730
        }
517
731
        
518
732
        void OnStreamInit(object sender, ElementStream stream)
520
734
            Trace.Call(sender, stream);
521
735
 
522
736
            stream.AddType("own-message", "http://www.facebook.com/xmpp/messages", typeof(OwnMessageQuery));
 
737
            SupressLocalMessageEcho = false;
523
738
        }
524
739
 
525
740
        void OnProtocol(object sender, XmlElement tag)
578
793
            }
579
794
        }
580
795
 
 
796
        public void OnRosterItem(object sender, Item ri)
 
797
        {
 
798
            string jid = ri.JID.Bare;
 
799
 
 
800
            if (ContactChat == null) return;
 
801
            lock (ContactChat) {
 
802
                PersonModel oldp = ContactChat.GetPerson(jid);
 
803
                if (oldp == null) {
 
804
                    // doesn't exist, don't need to do anything
 
805
                    return;
 
806
                }
 
807
                PersonModel newp = CreatePerson(jid);
 
808
                Session.UpdatePersonInGroupChat(ContactChat, oldp, newp);
 
809
            }
 
810
        }
 
811
 
 
812
        void OnPresence(object sender, Presence pres)
 
813
        {
 
814
            JID jid = pres.From;
 
815
            var groupChat = (XmppGroupChatModel) Session.GetChat(jid.Bare, ChatType.Group, this);
 
816
 
 
817
            MessageBuilder builder = CreateMessageBuilder();
 
818
            builder.AppendEventPrefix();
 
819
            PersonModel person = null;
 
820
            if (groupChat != null) {
 
821
                string displayName = jid.Resource ?? jid.Bare;
 
822
                person = new PersonModel("", displayName, "", "", this);
 
823
            } else {
 
824
                person = CreatePerson(jid.Bare);
 
825
            }
 
826
            builder.AppendIdendityName(person);
 
827
            if (jid != person.IdentityName) {
 
828
                builder.AppendText(" [{0}]", jid);
 
829
            }
 
830
 
 
831
            switch (pres.Type) {
 
832
                case PresenceType.available:
 
833
                    // groupchat is already managed
 
834
                    if (groupChat == null) {
 
835
                        if (ContactChat != null) {
 
836
                            // anyone who is online/away/dnd will be added to the list
 
837
                            lock (ContactChat) {
 
838
                                PersonModel p = ContactChat.GetPerson(jid.Bare);
 
839
                                if (p != null) {
 
840
                                    // p already exists, don't add a new person
 
841
                                    Session.UpdatePersonInGroupChat(ContactChat, p, person);
 
842
                                } else {
 
843
                                    Session.AddPersonToGroupChat(ContactChat, person);
 
844
                                }
 
845
                            }
 
846
                        }
 
847
                    }
 
848
                    if (pres.Show == null) {
 
849
                        builder.AppendText(_(" is now available"));
 
850
                    } else if (pres.Show == "away") {
 
851
                        builder.AppendText(_(" is now away"));
 
852
                    } else if (pres.Show == "dnd") {
 
853
                        builder.AppendText(_(" wishes not to be disturbed"));
 
854
                    } else {
 
855
                        builder.AppendText(_(" set status to {0}"), pres.Show);
 
856
                    }
 
857
                    if (pres.Status == null) break;
 
858
                    if (pres.Status.Length == 0) break;
 
859
                    builder.AppendText(": {0}", pres.Status);
 
860
                    break;
 
861
                case PresenceType.unavailable:
 
862
                    builder.AppendText(_(" is now offline"));
 
863
                    if(groupChat == null) {
 
864
                        if (ContactChat != null) {
 
865
                            lock (ContactChat) {
 
866
                                PersonModel p = ContactChat.GetPerson(jid.Bare);
 
867
                                if (p == null) {
 
868
                                    // doesn't exist, got an offline message w/o a preceding online message?
 
869
                                    return;
 
870
                                }
 
871
                                Session.RemovePersonFromGroupChat(ContactChat, p);
 
872
                            }
 
873
                        }
 
874
                    }
 
875
                    break;
 
876
                case PresenceType.subscribe:
 
877
                    builder.AppendText(_(" wishes to subscribe to you"));
 
878
                    break;
 
879
                case PresenceType.subscribed:
 
880
                    builder.AppendText(_(" allows you to subscribe"));
 
881
                    break;
 
882
            }
 
883
            if (groupChat != null) {
 
884
                Session.AddMessageToChat(groupChat, builder.ToMessage());
 
885
            } else if (ContactChat != null) {
 
886
                Session.AddMessageToChat(ContactChat, builder.ToMessage());
 
887
            }
 
888
            var personChat = Session.GetChat(jid.Bare, ChatType.Person, this);
 
889
            if (personChat != null) {
 
890
                Session.AddMessageToChat(personChat, builder.ToMessage());
 
891
            }
 
892
        }
 
893
 
581
894
        private void OnMessage(object sender, Message msg)
582
895
        {
583
896
            if (msg.Body == null) {
594
907
            ChatModel chat = null;
595
908
            PersonModel person = null;
596
909
            if (msg.Type != XmppMessageType.groupchat) {
597
 
                string jid = msg.From.Bare;
598
 
                var contact = _RosterManager[jid];
599
 
                string nickname = null;
600
 
                if (contact == null || String.IsNullOrEmpty(contact.Nickname)) {
601
 
                    nickname = jid;
602
 
                } else {
603
 
                    nickname = contact.Nickname;
604
 
                }
605
 
                PersonChatModel personChat = (PersonChatModel) Session.GetChat(jid, ChatType.Person, this);
 
910
                var sender_jid = msg.From.Bare;
 
911
                var personChat = (PersonChatModel) Session.GetChat(
 
912
                    sender_jid, ChatType.Person, this
 
913
                );
606
914
                if (personChat == null) {
607
 
                    person = new PersonModel(jid, nickname, NetworkID,
608
 
                                             Protocol, this);
 
915
                    person = CreatePerson(msg.From);
609
916
                    personChat = Session.CreatePersonChat(
610
 
                        person, jid, nickname, this
 
917
                        person, sender_jid, person.IdentityName, this
611
918
                    );
612
919
                    Session.AddChat(personChat);
613
920
                    Session.SyncChat(personChat);
618
925
            } else {
619
926
                string group_jid = msg.From.Bare;
620
927
                string group_name = group_jid;
621
 
                string sender_jid = msg.From.ToString();
622
928
                XmppGroupChatModel groupChat = (XmppGroupChatModel) Session.GetChat(group_jid, ChatType.Group, this);
623
929
                if (groupChat == null) {
624
 
                    // FIXME shouldn't happen?
625
930
                    groupChat = Session.CreateChat<XmppGroupChatModel>(
626
931
                        group_jid, group_name, this
627
932
                    );
628
933
                    Session.AddChat(groupChat);
629
 
                    Session.SyncChat(groupChat);
630
934
                }
631
935
                // resource can be empty for room messages
632
936
                var sender_id = msg.From.Resource ?? msg.From.Bare;
659
963
            if (display) {
660
964
                var builder = CreateMessageBuilder();
661
965
                if (msg.Type != XmppMessageType.error) {
662
 
                    builder.AppendMessage(person, msg.Body);
 
966
                    if (chat is PersonChatModel) {
 
967
                        // private message
 
968
                        builder.AppendSenderPrefix(person, true);
 
969
                        builder.AppendMessage(msg.Body);
 
970
                        builder.MarkHighlights();
 
971
                    } else if (chat is XmppGroupChatModel) {
 
972
                        // public message
 
973
                        builder.AppendMessage(person, msg.Body);
 
974
                        // mark highlights only for received messages
 
975
                        var muc = (XmppGroupChatModel) chat;
 
976
                        if (person.ID != muc.OwnNickname) {
 
977
                            builder.MarkHighlights();
 
978
                        }
 
979
                    }
663
980
                } else {
664
981
                    // TODO: nicer formatting
665
982
                    builder.AppendMessage(msg.Error.ToString());
688
1005
                // we send this message from Smuxi, nothing to do...
689
1006
                return;
690
1007
            }
 
1008
            
 
1009
            if (!SupressLocalMessageEcho && (query.Body == LastSentMessage)) {
 
1010
                SupressLocalMessageEcho = true;
 
1011
                return;
 
1012
            }
691
1013
 
692
1014
            var target_jid = query.To.Bare;
693
 
            var contact = _RosterManager[target_jid];
694
 
            string nickname = null;
695
 
            if (contact == null || String.IsNullOrEmpty(contact.Nickname)) {
696
 
                nickname = target_jid;
697
 
            } else {
698
 
                nickname = contact.Nickname;
699
 
            }
700
1015
            var chat = (PersonChatModel) Session.GetChat(target_jid,
701
1016
                                                         ChatType.Person, this);
702
1017
            if (chat == null) {
703
 
                var person = new PersonModel(target_jid, nickname, NetworkID,
704
 
                                             Protocol, this);
705
 
                chat = Session.CreatePersonChat(
706
 
                    person, target_jid, nickname, this
707
 
                );
 
1018
                var person = CreatePerson(query.To);
 
1019
                chat = Session.CreatePersonChat(person, this);
708
1020
                Session.AddChat(chat);
709
1021
                Session.SyncChat(chat);
710
1022
            }
732
1044
        private void AddPersonToGroup(Room room, string nickname)
733
1045
        {
734
1046
            string jid = room.JID.Bare;
735
 
            var chat = (GroupChatModel) Session.GetChat(jid, ChatType.Group, this);
 
1047
            var chat = (XmppGroupChatModel) Session.GetChat(jid, ChatType.Group, this);
736
1048
            // first notice we're joining a group chat is the participant info:
737
1049
            if (chat == null) {
738
1050
                chat = Session.CreateChat<XmppGroupChatModel>(jid, jid, this);
 
1051
                chat.OwnNickname = room.Nickname;
739
1052
                Session.AddChat(chat);
 
1053
            }
 
1054
 
 
1055
            lock (chat) {
 
1056
                if (chat.UnsafePersons.ContainsKey(nickname)) {
 
1057
                    return;
 
1058
                }
 
1059
                // manual construction is necessary for group chats
 
1060
                var person = new PersonModel(nickname, nickname, NetworkID, Protocol, this);
 
1061
                if (chat.IsSynced) {
 
1062
                    Session.AddPersonToGroupChat(chat, person);
 
1063
                } else {
 
1064
                    chat.UnsafePersons.Add(nickname, person);
 
1065
                }
 
1066
            }
 
1067
 
 
1068
            // did I join? then the chat roster is fully received
 
1069
            if (!chat.IsSynced && nickname == room.Nickname) {
 
1070
                chat.IsSynced = true;
740
1071
                Session.SyncChat(chat);
741
1072
            }
742
 
 
743
 
            PersonModel person;
744
 
            lock(chat.UnsafePersons) {
745
 
                person = chat.GetPerson(nickname);
746
 
                if (person != null) {
747
 
                    return;
748
 
                }
749
 
 
750
 
                person = new PersonModel(nickname, nickname,
751
 
                                         NetworkID, Protocol, this);
752
 
                chat.UnsafePersons.Add(nickname, person);
753
 
                Session.AddPersonToGroupChat(chat, person);
754
 
            }
755
1073
        }
756
1074
        
757
1075
        public void OnParticipantLeave(Room room, RoomParticipant roomParticipant)
760
1078
            var chat = (GroupChatModel) Session.GetChat(jid, ChatType.Group, this);
761
1079
            string nickname = roomParticipant.Nick;
762
1080
 
763
 
            PersonModel person;
764
 
            lock(chat.UnsafePersons) {
765
 
                person = chat.GetPerson(nickname);
 
1081
            lock (chat) {
 
1082
                var person = chat.GetPerson(nickname);
766
1083
                if (person == null) {
767
1084
                    return;
768
1085
                }
769
1086
 
770
 
                chat.UnsafePersons.Remove(nickname);
771
1087
                Session.RemovePersonFromGroupChat(chat, person);
772
1088
            }
773
1089
        }
795
1111
 
796
1112
            var builder = CreateMessageBuilder();
797
1113
            builder.AppendEventPrefix();
798
 
            builder.AppendText(_("Error: {0}"), String.Empty);
 
1114
            builder.AppendErrorText(_("Error: {0}"), String.Empty);
799
1115
            builder.AppendMessage(ex.Message);
800
 
            Session.AddMessageToChat(_NetworkChat, builder.ToMessage());
 
1116
            Session.AddMessageToChat(NetworkChat, builder.ToMessage());
801
1117
        }
802
1118
 
803
1119
        void OnAuthenticate(object sender)
806
1122
 
807
1123
            IsConnected = true;
808
1124
 
809
 
            Session.AddTextToChat(_NetworkChat, "Authenticated");
 
1125
            var builder = CreateMessageBuilder();
 
1126
            builder.AppendEventPrefix();
 
1127
            builder.AppendText(_("Authenticated"));
 
1128
            Session.AddMessageToChat(Chat, builder.ToMessage());
810
1129
 
811
1130
            // send initial presence
812
1131
            SetPresenceStatus(PresenceStatus.Online, null);
814
1133
            OnConnected(EventArgs.Empty);
815
1134
        }
816
1135
 
817
 
        private void ApplyConfig(UserConfig config, ServerModel server)
 
1136
        private void ApplyConfig(UserConfig config, XmppServerModel server)
818
1137
        {
819
1138
            if (server.Username.Contains("@")) {
820
1139
                var jid_user = server.Username.Split('@')[0];
821
1140
                var jid_host = server.Username.Split('@')[1];
822
 
                _JabberClient.NetworkHost = server.Hostname;
823
 
                _JabberClient.User = jid_user;
824
 
                _JabberClient.Server = jid_host;
 
1141
                JabberClient.NetworkHost = server.Hostname;
 
1142
                JabberClient.User = jid_user;
 
1143
                JabberClient.Server = jid_host;
825
1144
            } else {
826
 
                _JabberClient.Server = server.Hostname;
827
 
                _JabberClient.User = server.Username;
 
1145
                JabberClient.Server = server.Hostname;
 
1146
                JabberClient.User = server.Username;
828
1147
            }
829
 
            _JabberClient.Port = server.Port;
830
 
            _JabberClient.Password = server.Password;
 
1148
            JabberClient.Port = server.Port;
 
1149
            JabberClient.Password = server.Password;
 
1150
 
 
1151
            Me = CreatePerson(
 
1152
                String.Format("{0}@{1}",
 
1153
                    JabberClient.User,
 
1154
                    JabberClient.Server
 
1155
                ),
 
1156
                JabberClient.User
 
1157
            );
 
1158
            Me.IdentityNameColored.ForegroundColor = new TextColor(0, 0, 255);
 
1159
            Me.IdentityNameColored.BackgroundColor = TextColor.None;
 
1160
            Me.IdentityNameColored.Bold = true;
831
1161
 
832
1162
            // XMPP specific settings
833
 
            if (server is XmppServerModel) {
834
 
                var xmppServer = (XmppServerModel) server;
835
 
                _JabberClient.Resource = xmppServer.Resource;
836
 
            }
837
 
 
838
 
            // fallback
839
 
            if (String.IsNullOrEmpty(_JabberClient.Resource)) {
840
 
                _JabberClient.Resource = "smuxi";
841
 
            }
842
 
 
843
 
            _JabberClient.OnInvalidCertificate -= ValidateCertificate;
844
 
 
845
 
            _JabberClient.AutoStartTLS = server.UseEncryption;
 
1163
            JabberClient.Resource = server.Resource;
 
1164
 
 
1165
            JabberClient.OnInvalidCertificate -= ValidateCertificate;
 
1166
 
 
1167
            JabberClient.AutoStartTLS = server.UseEncryption;
846
1168
            if (!server.ValidateServerCertificate) {
847
 
                _JabberClient.OnInvalidCertificate += ValidateCertificate;
 
1169
                JabberClient.OnInvalidCertificate += ValidateCertificate;
848
1170
            }
849
1171
 
850
1172
            var proxySettings = new ProxySettings();
854
1176
                                          server.Hostname, server.Port);
855
1177
            var proxy = proxySettings.GetWebProxy(serverUri);
856
1178
            if (proxy == null) {
857
 
                _JabberClient.Proxy = XmppProxyType.None;
 
1179
                JabberClient.Proxy = XmppProxyType.None;
858
1180
            } else {
859
1181
                var proxyScheme = proxy.Address.Scheme;
860
1182
                var xmppProxyType = XmppProxyType.None;
869
1191
                                  proxyScheme, ex);
870
1192
#endif
871
1193
                }
872
 
                _JabberClient.Proxy = xmppProxyType;
873
 
                _JabberClient.ProxyHost = proxy.Address.Host;
874
 
                _JabberClient.ProxyPort = proxy.Address.Port;
875
 
                _JabberClient.ProxyUsername = proxySettings.ProxyUsername;
876
 
                _JabberClient.ProxyPassword = proxySettings.ProxyPassword;
 
1194
                JabberClient.Proxy = xmppProxyType;
 
1195
                JabberClient.ProxyHost = proxy.Address.Host;
 
1196
                JabberClient.ProxyPort = proxy.Address.Port;
 
1197
                JabberClient.ProxyUsername = proxySettings.ProxyUsername;
 
1198
                JabberClient.ProxyPassword = proxySettings.ProxyPassword;
877
1199
            }
878
1200
        }
879
1201
 
885
1207
            return true;
886
1208
        }
887
1209
 
 
1210
        PersonModel CreatePerson(JID jid)
 
1211
        {
 
1212
            if (jid == null) {
 
1213
                throw new ArgumentNullException("jid");
 
1214
            }
 
1215
            var contact = RosterManager[jid.Bare];
 
1216
            string nickname = null;
 
1217
            if (contact == null || String.IsNullOrEmpty(contact.Nickname)) {
 
1218
                nickname = jid.Bare;
 
1219
            } else {
 
1220
                nickname = contact.Nickname;
 
1221
            }
 
1222
            return CreatePerson(jid.Bare, nickname);
 
1223
        }
 
1224
 
 
1225
        PersonModel CreatePerson(string jid, string nickname)
 
1226
        {
 
1227
            return new PersonModel(jid, nickname, NetworkID, Protocol, this);
 
1228
        }
 
1229
 
888
1230
        private static string _(string msg)
889
1231
        {
890
1232
            return Mono.Unix.Catalog.GetString(msg);