2
/* Ekiga -- A VoIP and Video-Conferencing application
3
* Copyright (C) 2000-2006 Damien Sandras
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20
* Ekiga is licensed under the GPL license and as a special exception,
21
* you have permission to link or otherwise combine this program with the
22
* programs OPAL, OpenH323 and PWLIB, and distribute the combination,
23
* without applying the requirements of the GNU GPL to the OPAL, OpenH323
24
* and PWLIB programs, as long as you do follow the requirements of the
25
* GNU GPL for all the rest of the software thus combined.
30
* sipendpoint.cpp - description
31
* --------------------------------
32
* begin : Wed 8 Dec 2004
33
* copyright : (C) 2000-2006 by Damien Sandras
34
* description : This file contains the SIP Endpoint class.
39
#include "../../config.h"
47
#include "preferences.h"
49
#include "statusicon.h"
58
#include <ptlib/ethsock.h>
64
GMSIPEndpoint::GMSIPEndpoint (GMManager & ep)
65
: SIPEndPoint (ep), endpoint (ep)
67
NoAnswerTimer.SetNotifier (PCREATE_NOTIFIER (OnNoAnswerTimeout));
71
GMSIPEndpoint::~GMSIPEndpoint ()
77
GMSIPEndpoint::Init ()
79
GtkWidget *main_window = NULL;
81
gchar *outbound_proxy_host = NULL;
82
int binding_timeout = 60;
84
main_window = GnomeMeeting::Process ()->GetMainWindow ();
86
gnomemeeting_threads_enter ();
87
outbound_proxy_host = gm_conf_get_string (SIP_KEY "outbound_proxy_host");
88
binding_timeout = gm_conf_get_int (NAT_KEY "binding_timeout");
89
gnomemeeting_threads_leave ();
93
SetAckTimeout (PTimeInterval (0, 32));
94
SetPduCleanUpTimeout (PTimeInterval (0, 1));
95
SetInviteTimeout (PTimeInterval (0, 6));
96
SetNonInviteTimeout (PTimeInterval (0, 6));
97
SetNATBindingTimeout (PTimeInterval (0, binding_timeout));
98
SetRetryTimeouts (500, 4000);
102
/* Update the User Agent */
103
SetUserAgent ("Ekiga/" PACKAGE_VERSION);
106
/* Initialise internal parameters */
107
if (outbound_proxy_host && !PString (outbound_proxy_host).IsEmpty ())
108
SetProxy (outbound_proxy_host);
109
SetNATBindingRefreshMethod (SIPEndPoint::EmptyRequest);
112
g_free (outbound_proxy_host);
117
GMSIPEndpoint::StartListener (PString iface,
122
PIPSocket::InterfaceTable ifaces;
127
gboolean found = FALSE;
129
gchar *listen_to = NULL;
131
RemoveListener (NULL);
133
/* Detect the valid interfaces */
134
PIPSocket::GetInterfaceTable (ifaces);
136
while (i < ifaces.GetSize ()) {
138
ip = " [" + ifaces [i].GetAddress ().AsString () + "]";
140
if (ifaces [i].GetName () + ip == iface) {
142
g_strdup_printf ("udp$%s:%d",
143
(const char *) ifaces [i].GetAddress().AsString(),
152
pos = iface.Find("[");
153
if (pos != P_MAX_INDEX)
154
iface_noip = iface.Left (pos).Trim ();
155
while (i < ifaces.GetSize() && !found) {
157
if (ifaces [i].GetName () == iface_noip) {
159
g_strdup_printf ("udp$%s:%d",
160
(const char *) ifaces [i].GetAddress().AsString(),
168
/* Start the listener thread for incoming calls */
172
ok = StartListeners (PStringArray (listen_to));
180
GMSIPEndpoint::SetUserNameAndAlias ()
182
PString default_local_name;
184
default_local_name = endpoint.GetDefaultDisplayName ();
186
if (!default_local_name.IsEmpty ()) {
188
SetDefaultDisplayName (default_local_name);
194
GMSIPEndpoint::SetUserInputMode ()
196
// Do nothing, only RFC2833 is supported.
201
GMSIPEndpoint::OnRegistered (const PString & domain,
202
const PString & username,
205
GtkWidget *accounts_window = NULL;
206
GtkWidget *history_window = NULL;
207
GtkWidget *main_window = NULL;
209
GObject *dbus_component = NULL;
214
accounts_window = GnomeMeeting::Process ()->GetAccountsWindow ();
215
main_window = GnomeMeeting::Process ()->GetMainWindow ();
216
history_window = GnomeMeeting::Process ()->GetHistoryWindow ();
218
dbus_component = GnomeMeeting::Process ()->GetDbusComponent ();
221
gnomemeeting_threads_enter ();
222
/* Registering is ok */
223
if (wasRegistering) {
225
msg = g_strdup_printf (_("Registered to %s"),
226
(const char *) domain);
227
gm_accounts_window_update_account_state (accounts_window,
229
(const char *) domain,
230
(const char *) username,
236
msg = g_strdup_printf (_("Unregistered from %s"),
237
(const char *) domain);
238
gm_accounts_window_update_account_state (accounts_window,
240
(const char *) domain,
241
(const char *) username,
247
gnomemeeting_dbus_component_account_registration (dbus_component,
252
gm_history_window_insert (history_window, "%s", msg);
253
gm_main_window_flash_message (main_window, "%s", msg);
254
if (endpoint.GetCallingState() == GMManager::Standby)
255
gm_main_window_set_account_info (main_window,
256
endpoint.GetRegisteredAccounts());
257
gnomemeeting_threads_leave ();
259
/* Signal the SIPEndpoint */
260
SIPEndPoint::OnRegistered (domain, username, wasRegistering);
267
GMSIPEndpoint::OnRegistrationFailed (const PString & host,
268
const PString & user,
269
SIP_PDU::StatusCodes r,
272
GtkWidget *accounts_window = NULL;
273
GtkWidget *history_window = NULL;
274
GtkWidget *main_window = NULL;
276
gchar *msg_reason = NULL;
279
main_window = GnomeMeeting::Process ()->GetMainWindow ();
280
accounts_window = GnomeMeeting::Process ()->GetAccountsWindow ();
281
history_window = GnomeMeeting::Process ()->GetHistoryWindow ();
283
gnomemeeting_threads_enter ();
284
/* Registering is ok */
287
case SIP_PDU::Failure_BadRequest:
288
msg_reason = g_strdup (_("Bad request"));
291
case SIP_PDU::Failure_PaymentRequired:
292
msg_reason = g_strdup (_("Payment required"));
295
case SIP_PDU::Failure_UnAuthorised:
296
case SIP_PDU::Failure_Forbidden:
297
msg_reason = g_strdup (_("Forbidden"));
300
case SIP_PDU::Failure_RequestTimeout:
301
msg_reason = g_strdup (_("Timeout"));
304
case SIP_PDU::Failure_Conflict:
305
msg_reason = g_strdup (_("Conflict"));
308
case SIP_PDU::Failure_TemporarilyUnavailable:
309
msg_reason = g_strdup (_("Temporarily unavailable"));
312
case SIP_PDU::Failure_NotAcceptable:
313
msg_reason = g_strdup (_("Not Acceptable"));
317
msg_reason = g_strdup (_("Registration failed"));
320
if (wasRegistering) {
322
msg = g_strdup_printf (_("Registration failed: %s"),
325
gm_accounts_window_update_account_state (accounts_window,
329
_("Registration failed"),
334
msg = g_strdup_printf (_("Unregistration failed: %s"),
337
gm_accounts_window_update_account_state (accounts_window,
341
_("Unregistration failed"),
345
gm_history_window_insert (history_window, "%s", msg);
346
gm_main_window_push_message (main_window, "%s", msg);
347
gnomemeeting_threads_leave ();
349
/* Signal the SIP Endpoint */
350
SIPEndPoint::OnRegistrationFailed (host, user, r, wasRegistering);
358
GMSIPEndpoint::OnIncomingConnection (OpalConnection &connection)
360
PSafePtr<OpalConnection> con = NULL;
361
PSafePtr<OpalCall> call = NULL;
363
gchar *forward_host = NULL;
365
IncomingCallMode icm;
366
gboolean busy_forward = FALSE;
367
gboolean always_forward = FALSE;
368
int no_answer_timeout = FALSE;
374
PTRACE (3, "GMSIPEndpoint\tIncoming connection");
376
gnomemeeting_threads_enter ();
377
forward_host = gm_conf_get_string (SIP_KEY "forward_host");
378
busy_forward = gm_conf_get_bool (CALL_FORWARDING_KEY "forward_on_busy");
379
always_forward = gm_conf_get_bool (CALL_FORWARDING_KEY "always_forward");
381
(IncomingCallMode) gm_conf_get_int (CALL_OPTIONS_KEY "incoming_call_mode");
383
gm_conf_get_int (CALL_OPTIONS_KEY "no_answer_timeout");
384
gnomemeeting_threads_leave ();
386
call = endpoint.FindCallWithLock (endpoint.GetCurrentCallToken());
388
con = endpoint.GetConnection (call, TRUE);
389
if ((con && con->GetIdentifier () == connection.GetIdentifier())) {
393
if (icm == DO_NOT_DISTURB)
395
else if (forward_host && always_forward)
396
reason = 2; // Forward
397
/* We are in a call */
398
else if (endpoint.GetCallingState () != GMManager::Standby) {
400
if (forward_host && busy_forward)
401
reason = 2; // Forward
403
reason = 1; // Reject
405
else if (icm == AUTO_ANSWER)
406
reason = 4; // Auto Answer
408
reason = 0; // Ask the user
411
NoAnswerTimer.SetInterval (0, PMIN (no_answer_timeout, 60));
413
res = endpoint.OnIncomingConnection (connection, reason, forward_host);
415
g_free (forward_host);
422
GMSIPEndpoint::OnMWIReceived (const PString & remoteAddress,
423
const PString & user,
424
SIPMWISubscribe::MWIType type,
425
const PString & msgs)
427
GMManager *ep = NULL;
428
GMPCSSEndpoint *pcssEP = NULL;
430
GtkWidget *main_window = NULL;
431
GtkWidget *accounts_window = NULL;
435
if (endpoint.GetMWI (remoteAddress, user) != msgs) {
437
total = endpoint.GetMWI ().AsInteger ();
440
endpoint.AddMWI (remoteAddress, user, msgs);
442
main_window = GnomeMeeting::Process ()->GetMainWindow ();
443
accounts_window = GnomeMeeting::Process ()->GetAccountsWindow ();
445
gnomemeeting_threads_enter ();
446
gm_main_window_push_message (main_window,
447
endpoint.GetMissedCallsNumber (),
449
gm_accounts_window_update_account_state (accounts_window,
454
(const char *) msgs);
455
gnomemeeting_threads_leave ();
457
/* Sound event if new voice mail */
458
if (endpoint.GetMWI ().AsInteger () > total) {
460
ep = GnomeMeeting::Process ()->GetManager ();
461
pcssEP = ep->GetPCSSEndpoint ();
462
pcssEP->PlaySoundEvent ("new_voicemail_sound");
469
GMSIPEndpoint::OnReceivedMESSAGE (OpalTransport & transport,
472
PString *last = NULL;
475
PString from = pdu.GetMIME().GetFrom();
476
PINDEX j = from.Find (';');
477
if (j != P_MAX_INDEX)
478
from = from.Left(j); // Remove all parameters
480
if (j != P_MAX_INDEX && from.Find ('>') == P_MAX_INDEX)
483
PWaitAndSignal m(msgDataMutex);
484
last = msgData.GetAt (SIPURL (from).AsString ());
485
if (!last || *last != pdu.GetMIME ().GetCallID ()) {
487
val = new PString (pdu.GetMIME ().GetCallID ());
488
msgData.SetAt (SIPURL (from).AsString (), val);
489
OnMessageReceived(from, pdu.GetEntityBody());
495
GMSIPEndpoint::OnMessageReceived (const SIPURL & from,
496
const PString & body)
498
GMManager *ep = NULL;
499
GMPCSSEndpoint *pcssEP = NULL;
501
GtkWidget *chat_window = NULL;
502
GtkWidget *statusicon = NULL;
504
gboolean chat_window_visible = FALSE;
506
chat_window = GnomeMeeting::Process ()->GetChatWindow ();
507
statusicon = GnomeMeeting::Process ()->GetStatusicon ();
509
SIPEndPoint::OnMessageReceived (from, body);
511
gnomemeeting_threads_enter ();
512
gm_text_chat_window_insert (chat_window, from.AsString (),
513
from.GetDisplayName (), (const char *) body, 1);
514
chat_window_visible = gnomemeeting_window_is_visible (chat_window);
515
gnomemeeting_threads_leave ();
517
if (!chat_window_visible) {
519
gnomemeeting_threads_enter ();
520
gm_statusicon_signal_message (statusicon, TRUE);
521
gnomemeeting_threads_leave ();
523
ep = GnomeMeeting::Process ()->GetManager ();
524
pcssEP = ep->GetPCSSEndpoint ();
525
pcssEP->PlaySoundEvent ("new_message_sound");
531
GMSIPEndpoint::OnMessageFailed (const SIPURL & messageUrl,
532
SIP_PDU::StatusCodes reason)
534
GtkWidget *chat_window = NULL;
537
chat_window = GnomeMeeting::Process ()->GetChatWindow ();
541
case SIP_PDU::Failure_NotFound:
542
msg = g_strdup (_("Error: User not found"));
545
case SIP_PDU::Failure_TemporarilyUnavailable:
546
msg = g_strdup (_("Error: User offline"));
549
case SIP_PDU::Failure_UnAuthorised:
550
case SIP_PDU::Failure_Forbidden:
551
msg = g_strdup (_("Error: Forbidden"));
554
case SIP_PDU::Failure_RequestTimeout:
555
msg = g_strdup (_("Error: Timeout"));
559
msg = g_strdup (_("Error: Failed to transmit message"));
562
gnomemeeting_threads_enter ();
563
gm_text_chat_window_insert (chat_window, messageUrl.AsString (),
565
gnomemeeting_threads_leave ();
572
GMSIPEndpoint::GetRegisteredAccounts ()
574
return SIPEndPoint::GetRegistrationsCount ();
579
GMSIPEndpoint::GetRegisteredPartyName (const PString & host)
581
GmAccount *account = NULL;
584
SIPURL registration_address;
586
PSafePtr<SIPInfo> info = activeSIPInfo.FindSIPInfoByDomain(host, SIP_PDU::Method_REGISTER, PSafeReadOnly);
589
registration_address = info->GetRegistrationAddress();
591
account = gnomemeeting_get_default_account ("SIP");
592
if (account && account->enabled) {
594
if (info == NULL || registration_address.GetHostName () == account->host) {
596
if (PString(account->username).Find("@") == P_MAX_INDEX)
597
url = PString (account->username) + "@" + PString (account->host);
599
url = PString (account->username);
605
return registration_address;
607
return SIPEndPoint::GetDefaultRegisteredPartyName ();
612
GMSIPEndpoint::OnEstablished (OpalConnection &connection)
614
NoAnswerTimer.Stop ();
616
PTRACE (3, "GMSIPEndpoint\t SIP connection established");
617
SIPEndPoint::OnEstablished (connection);
622
GMSIPEndpoint::OnReleased (OpalConnection &connection)
624
NoAnswerTimer.Stop ();
626
PTRACE (3, "GMSIPEndpoint\t SIP connection released");
627
SIPEndPoint::OnReleased (connection);
632
GMSIPEndpoint::OnNoAnswerTimeout (PTimer &,
635
gchar *forward_host = NULL;
636
gboolean forward_on_no_answer = FALSE;
638
if (endpoint.GetCallingState () == GMManager::Called) {
640
gnomemeeting_threads_enter ();
641
forward_host = gm_conf_get_string (SIP_KEY "forward_host");
642
forward_on_no_answer =
643
gm_conf_get_bool (CALL_FORWARDING_KEY "forward_on_no_answer");
644
gnomemeeting_threads_leave ();
646
if (forward_host && forward_on_no_answer) {
648
PSafePtr<OpalCall> call =
649
endpoint.FindCallWithLock (endpoint.GetCurrentCallToken ());
650
PSafePtr<OpalConnection> con =
651
endpoint.GetConnection (call, TRUE);
653
con->ForwardCall (forward_host);
656
ClearAllCalls (OpalConnection::EndedByNoAnswer, FALSE);
658
g_free (forward_host);