Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/releaseWindowsTestOne
  • release/windowsReleaseTest
  • release/releaseTest
  • release/releaseWindowsTest
  • release/201910
  • release/qt/201910
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • 4.0.0
  • 2.2.0
  • 2.1.0
  • 2.0.1
  • 2.0.0
  • 1.4.1
  • 1.4.0
  • 1.3.0
  • 1.2.0
  • 1.1.0
30 results

actions.c

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    actions.c 17.51 KiB
    /*
     *  Copyright (C) 2007 - 2008 Savoir-Faire Linux inc.
     *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
     *  Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com>
     *                                                                              
     *  This program is free software; you can redistribute it and/or modify
     *  it under the terms of the GNU General Public License as published by
     *  the Free Software Foundation; either version 3 of the License, or
     *  (at your option) any later version.
     *                                                                                
     *  This program is distributed in the hope that it will be useful,
     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     *  GNU General Public License for more details.
     *                                                                              
     *  You should have received a copy of the GNU General Public License
     *  along with this program; if not, write to the Free Software
     *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     */
    
    #include <actions.h>
    #include <calltree.h>
    #include <dbus.h>
    #include <mainwindow.h>
    #include <menus.h>
    #include <statusicon.h>
    #include <calltab.h>
    #include <historyfilter.h>
    
    #include <gtk/gtk.h>
    #include <string.h>
    #include <glib/gprintf.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    guint voice_mails;
    
    void
    sflphone_notify_voice_mail ( const gchar* accountID , guint count )
    {
        gchar *id;
        gchar *current;
        
        // We want to notify only for the default current account; ie the first in the list
        id = g_strdup( accountID );
        current = account_list_get_current_id();
        if( strcmp( id, current ) != 0 )
            return;
    
        voice_mails = count ;
    
        if(count > 0)
        {
            gchar * message = g_new0(gchar, 50);
            if( count > 1)
                g_sprintf(message, _("%d voice mails"), count);
            else
                g_sprintf(message, _("%d voice mail"), count);	  
            statusbar_push_message(message,  __MSG_VOICE_MAILS);
            g_free(message);
        }
    	
        // TODO: add ifdef
        if( account_list_get_size() > 0 )
        {
            account_t* acc = account_list_get_by_id( id );
    	if( acc != NULL )
                notify_voice_mails( count , acc );	
        }
    }
    
    void
    status_bar_display_account( call_t* c)
    {
        gchar* msg;
        account_t* acc;
        if(c->accountID != NULL){
          acc = account_list_get_by_id(c->accountID);
          msg = g_markup_printf_escaped(_("%s account- %s") , 
    				  (gchar*)g_hash_table_lookup( acc->properties , ACCOUNT_TYPE), 
    				  (gchar*)g_hash_table_lookup( acc->properties , ACCOUNT_ALIAS));
          statusbar_push_message( msg , __MSG_ACCOUNT_DEFAULT);
          g_free(msg);
      }
    }
      
    
    gboolean
    sflphone_quit ()
    {
    	gboolean quit = FALSE;
    	guint count = call_list_get_size(current_calls);
    	if(count > 0){
    		quit = main_window_ask_quit();
    	}
    	else{
    		quit = TRUE;
    	}
    
    	if (quit)
    	{
    		dbus_unregister(getpid());
    		dbus_clean ();
    		//call_list_clean(); TODO
    		//account_list_clean()
    		gtk_main_quit ();
    	}
    	return quit;
    }
    
    void 
    sflphone_hold(call_t * c )
    {
    	c->state = CALL_STATE_HOLD;
    	update_call_tree(current_calls,c);
    	update_menus();
    }
    
    void 
    sflphone_ringing(call_t * c )
    {
    	c->state = CALL_STATE_RINGING;
    	update_call_tree(current_calls,c);
    	update_menus();
    }
    
    void
    sflphone_hung_up( call_t * c)
    {
      call_list_remove( current_calls, c->callID);
      update_call_tree_remove(current_calls, c);
      c->state = CALL_STATE_DIALING;
      update_menus();
    #if GTK_CHECK_VERSION(2,10,0)
      status_tray_icon_blink( FALSE );
    #endif
    }
    
    /** Internal to actions: Fill account list */
    	void
    sflphone_fill_account_list(gboolean toolbarInitialized)
    {
    
        gchar** array;
        gchar** accountID;
        unsigned int i;
    
    	account_list_clear ( );
    
    	array = (gchar **)dbus_account_list();
        if(array)
        {
    	    for (accountID = array; *accountID; accountID++)
    	    {
    		    account_t * a = g_new0(account_t,1);
    		    a->accountID = g_strdup(*accountID);
    		    account_list_add(a);
    	    }
    	    g_strfreev (array);
        }
    
    	for( i = 0; i < account_list_get_size(); i++)
    	{
    		account_t  * a = account_list_get_nth (i);
    		GHashTable * details = (GHashTable *) dbus_account_details(a->accountID);
    		a->properties = details;
    
    		gchar * status = g_hash_table_lookup(details, "Status");
    		if(strcmp(status, "REGISTERED") == 0)
    		{
    			a->state = ACCOUNT_STATE_REGISTERED;
    		}
    		else if(strcmp(status, "UNREGISTERED") == 0)
    		{
    			a->state = ACCOUNT_STATE_UNREGISTERED;
    		}
    		else if(strcmp(status, "TRYING") == 0)
    		{
    			a->state = ACCOUNT_STATE_TRYING;
    		}
    		else if(strcmp(status, "ERROR") == 0)
    		{
    			a->state = ACCOUNT_STATE_ERROR;
    		}
    		else if(strcmp( status , "ERROR_AUTH") == 0 )
    		{
    		  a->state = ACCOUNT_STATE_ERROR_AUTH;
    		}
    		else if(strcmp( status , "ERROR_NETWORK") == 0 )
    		{
    		  a->state = ACCOUNT_STATE_ERROR_NETWORK;
    		}
    		else if(strcmp( status , "ERROR_HOST") == 0 )
    		{
    		  a->state = ACCOUNT_STATE_ERROR_HOST;
    		}
    		else
    		{
    			a->state = ACCOUNT_STATE_INVALID;
    		}
    
    	}
    
    	// Prevent update being called when toolbar is not yet initialized
    	if(toolbarInitialized)
    		toolbar_update_buttons();
    }
    
    gboolean
    sflphone_init()
    {
    	current_calls = calltab_init();
    	history = calltab_init();
    	sleep(0.5);	
    	if(SHOW_SEARCHBAR)  histfilter = create_filter(GTK_TREE_MODEL(history->store));
    	account_list_init ();
            codec_list_init();
    	if(!dbus_connect ()){
    	
    		main_window_error_message(_("Unable to connect to the SFLphone server.\nMake sure the daemon is running."));
    		return FALSE;
    	}
    	else 
    	{
    		dbus_register(getpid(), "Gtk+ Client");
    		sflphone_fill_account_list(FALSE);
    		sflphone_fill_codec_list();
    		sflphone_set_current_account();
    		return TRUE;
    	}
    }
    
    void 
    sflphone_hang_up()
    {
    	call_t * selectedCall = call_get_selected(current_calls);
    	if(selectedCall)
    	{
    		switch(selectedCall->state)
    		{
    			case CALL_STATE_DIALING:
    				dbus_hang_up (selectedCall);
    				break;
    			case CALL_STATE_RINGING:
    				dbus_hang_up (selectedCall);
    				selectedCall->state = CALL_STATE_DIALING;
    				selectedCall->_stop = 0;
    				break;
    			case CALL_STATE_CURRENT:
    			case CALL_STATE_HOLD:
    			case CALL_STATE_BUSY:
    			case CALL_STATE_FAILURE:
    				dbus_hang_up (selectedCall);
    				selectedCall->state = CALL_STATE_DIALING;
    				(void) time(&selectedCall->_stop);
    				break;
    			case CALL_STATE_INCOMING:  
    				dbus_refuse (selectedCall);
    				selectedCall->state = CALL_STATE_DIALING;
    				selectedCall->_stop = 0;
    				g_print("from sflphone_hang_up : "); stop_notification();
    				break;
    			case CALL_STATE_TRANSFERT:  
    				dbus_hang_up (selectedCall);
    				(void) time(&selectedCall->_stop);
    				break;
    			default:
    				g_warning("Should not happen in sflphone_hang_up()!");
    				break;
    		}
    	}
    	update_call_tree( history , selectedCall );
    }
    
    
    void 
    sflphone_pick_up()
    {
    	call_t * selectedCall = call_get_selected(active_calltree);
    	if(selectedCall)
    	{
    		switch(selectedCall->state)
    		{
    			case CALL_STATE_DIALING:
    				sflphone_place_call (selectedCall);
    				break;
    			case CALL_STATE_INCOMING:
    				selectedCall->history_state = INCOMING;
    				update_call_tree( history , selectedCall );
    				dbus_accept (selectedCall);
    				g_print("from sflphone_pick_up : "); stop_notification();
    				break;
    			case CALL_STATE_HOLD:
    				sflphone_new_call();
    				break;
    			case CALL_STATE_TRANSFERT:
    				dbus_transfert (selectedCall);
    				(void) time(&selectedCall->_stop);
    				break;
    			case CALL_STATE_CURRENT:
    				sflphone_new_call();
    				break;
    			case CALL_STATE_RINGING:
    				sflphone_new_call();
    				break;
    			default:
    				g_warning("Should not happen in sflphone_pick_up()!");
    				break;
    		}
    	}
    }
    
    void 
    sflphone_on_hold ()
    {
    	call_t * selectedCall = call_get_selected(current_calls);
    	if(selectedCall)
    	{
    		switch(selectedCall->state)
    		{
    			case CALL_STATE_CURRENT:
    				dbus_hold (selectedCall);
    				break;
    			default:
    				g_warning("Should not happen in sflphone_on_hold!");
    				break;
    		}
    	}
    }
    
    void 
    sflphone_off_hold ()
    {
    	call_t * selectedCall = call_get_selected(current_calls);
    	if(selectedCall)
    	{
    		switch(selectedCall->state)
    		{
    			case CALL_STATE_HOLD:
    				dbus_unhold (selectedCall);
    				break;
    			default:
    				g_warning("Should not happen in sflphone_off_hold ()!");
    				break;
    		}
    	}
    }
    
    
    void 
    sflphone_fail( call_t * c )
    {
    	c->state = CALL_STATE_FAILURE;
    	update_call_tree(current_calls,c);
    	update_menus();
    }
    
    void 
    sflphone_busy( call_t * c )
    {
    	c->state = CALL_STATE_BUSY;
    	update_call_tree(current_calls, c);
    	update_menus();
    }
    
    void 
    sflphone_current( call_t * c )
    {
      if( c->state != CALL_STATE_HOLD )
    	(void) time(&c->_start);
      c->state = CALL_STATE_CURRENT;
      update_call_tree(current_calls,c);
      update_menus();
    }
    
    void 
    sflphone_set_transfert()
    {
    	call_t * c = call_get_selected(current_calls);
    	if(c)
    	{
    		c->state = CALL_STATE_TRANSFERT;
    		c->to = g_strdup("");
    		update_call_tree(current_calls,c);
    		update_menus();
    	}
    	toolbar_update_buttons();
    }
    
    void 
    sflphone_unset_transfert()
    {
    	call_t * c = call_get_selected(current_calls);
    	if(c)
    	{
    		c->state = CALL_STATE_CURRENT;
    		c->to = g_strdup("");
    		update_call_tree(current_calls,c);
    		update_menus();
    	}
    	toolbar_update_buttons();
    }
    
    void
    sflphone_incoming_call (call_t * c) 
    {
    	c->history_state = MISSED;
    	call_list_add ( current_calls, c );
    	call_list_add( history, c );
    	update_call_tree_add( current_calls , c );
    	update_menus();
    	if( active_calltree == history )  switch_tab();
    }
    
    void
    process_dialing(call_t * c, guint keyval, gchar * key)
    {
    	// We stop the tone
    	if(strlen(c->to) == 0 && c->state != CALL_STATE_TRANSFERT){
    	  dbus_start_tone( FALSE , 0 );
    	  //dbus_play_dtmf( key );
    	}
    	switch (keyval)
    	{
    		case 65293: /* ENTER */
    		case 65421: /* ENTER numpad */
    			sflphone_place_call(c);
    			break;
    		case 65307: /* ESCAPE */
    			sflphone_hang_up(c);
    			break;
    		case 65288: /* BACKSPACE */
    			{  /* Brackets mandatory because of local vars */
    				gchar * before = c->to;
    				if(strlen(c->to) >= 1){
    					c->to = g_strndup(c->to, strlen(c->to) -1);
    					g_free(before);
    					g_print("TO: %s\n", c->to);
    
    					if(c->state == CALL_STATE_DIALING)
    					{
    						g_free(c->from);
    						c->from = g_strconcat("\"\" <", c->to, ">", NULL);
    					}
    					update_call_tree(current_calls,c);
    				} 
    				else if(strlen(c->to) == 0)
    				{
    				  if(c->state != CALL_STATE_TRANSFERT)
    					dbus_hang_up(c);
    				}
    			}
    			break;
    		case 65289: /* TAB */
    		case 65513: /* ALT */
    		case 65507: /* CTRL */
    		case 65515: /* SUPER */
    		case 65509: /* CAPS */
    			break;
    		default:
    			if (keyval < 255 || (keyval >65453 && keyval < 65466))
    			{ 
    				if(c->state != CALL_STATE_TRANSFERT)
    				  dbus_play_dtmf( key );
    				  gchar * before = c->to;
    				  c->to = g_strconcat(c->to, key, NULL);
    				  g_free(before);
    				  g_print("TO: %s\n", c->to);
    
    				if(c->state == CALL_STATE_DIALING)
    				{
    					g_free(c->from);
    					c->from = g_strconcat("\"\" <", c->to, ">", NULL);
    				}
    				update_call_tree(current_calls,c);
    			}
    			break;
    	}
    
    }
    
    
    call_t * 
    sflphone_new_call()
    {
    	// Play a tone when creating a new call
    	if( call_list_get_size(current_calls) == 0 )
    	  dbus_start_tone( TRUE , ( voice_mails > 0 )? TONE_WITH_MESSAGE : TONE_WITHOUT_MESSAGE) ;
    
    	call_t * c = g_new0 (call_t, 1);
    	c->state = CALL_STATE_DIALING;
    	c->from = g_strconcat("\"\" <>", NULL);
    
    	c->callID = g_new0(gchar, 30);
    	g_sprintf(c->callID, "%d", rand()); 
    
    	c->to = g_strdup("");
    
    	c->_start = 0;
    	c->_stop = 0;
    
    	call_list_add(current_calls,c);
    	update_call_tree_add(current_calls,c);  
    	update_menus();
    
    	return c;
    }
    
    
    void 
    sflphone_keypad( guint keyval, gchar * key)
    {
    
    	call_t * c = call_get_selected(current_calls);
    	if(c)
    	{
    		switch(c->state) 
    		{
    			case CALL_STATE_DIALING: // Currently dialing => edit number
    				process_dialing(c, keyval, key);
    				break;
    			case CALL_STATE_CURRENT:
    				switch (keyval)
    				{
    					case 65307: /* ESCAPE */
    						dbus_hang_up(c);
    						(void) time(&c->_stop);
    						update_call_tree( history , c );
    						break;
    					default:  
    						// To play the dtmf when calling mail box for instance
    						dbus_play_dtmf(key);
    						if (keyval < 255 || (keyval >65453 && keyval < 65466))
    						{ 
    							//gchar * temp = g_strconcat(call_get_number(c), key, NULL);
    							//gchar * before = c->from;
    							//c->from = g_strconcat("\"",call_get_name(c) ,"\" <", temp, ">", NULL);
    							//g_free(before);
    							//g_free(temp);
    							//update_call_tree(current_calls,c);
    						}
    						break;
    				}
    				break;
    			case CALL_STATE_INCOMING:
    				switch (keyval)
    				{
    					case 65293: /* ENTER */
    					case 65421: /* ENTER numpad */
    						c->history_state = INCOMING;
    						update_call_tree( history , c );
    						dbus_accept(c);
    						g_print("from sflphone_keypad ( enter ) : "); stop_notification();
    						break;
    					case 65307: /* ESCAPE */
    						dbus_refuse(c);
    						g_print("from sflphone_keypad ( escape ) : "); stop_notification();
    						break;
    				}
    				break;
    			case CALL_STATE_TRANSFERT:
    				switch (keyval)
    				{
    					case 65293: /* ENTER */
    					case 65421: /* ENTER numpad */
    						dbus_transfert(c);
    						(void) time(&c->_stop);
    						break;
    					case 65307: /* ESCAPE */
    						sflphone_unset_transfert(c); 
    						break;
    					default: // When a call is on transfert, typing new numbers will add it to c->to
    						process_dialing(c, keyval, key);
    						break;
    				}
    				break;
    			case CALL_STATE_HOLD:
    				switch (keyval)
    				{
    					case 65293: /* ENTER */
    					case 65421: /* ENTER numpad */
    						dbus_unhold(c);
    						break;
    					case 65307: /* ESCAPE */
    						dbus_hang_up(c);
    						break;
    					default: // When a call is on hold, typing new numbers will create a new call
    						process_dialing(sflphone_new_call(), keyval, key);
    						break;
    				}
    				break;
    			case CALL_STATE_RINGING:
    			case CALL_STATE_BUSY:
    			case CALL_STATE_FAILURE:
    				switch (keyval)
    				{
    					case 65307: /* ESCAPE */
    					  dbus_hang_up(c);
    					  c->_stop = 0;
    					  update_call_tree( history , c );
    					  break;
    				}
    				break;
    			default:
    				break;
    		} 
    	}
    	else 
    	{ // Not in a call, not dialing, create a new call 
    		//dbus_play_dtmf(key);
    		switch (keyval)
    		{
    			case 65293: /* ENTER */
    			case 65421: /* ENTER numpad */
    			case 65307: /* ESCAPE */
    				break;
    			default:
    				if( active_calltree == history )
    				  switch_tab();
    				process_dialing(sflphone_new_call(), keyval, key);
    				break;
    		}
    
    
    	}
     } 
    
    /*
     * Place a call with the current account.
     * If there is no default account selected, place a call with the first 
     * registered account of the account list
     * Else, popup an error message
     */
    void 
    sflphone_place_call ( call_t * c )
    {
      if(c->state == CALL_STATE_DIALING)
      {
        if( account_list_get_size() == 0 )
        {
          notify_no_accounts();
          sflphone_fail(c);
        }
        else if( account_list_get_by_state( ACCOUNT_STATE_REGISTERED ) == NULL )
        {
          notify_no_registered_accounts();
          sflphone_fail(c);
        }
        else
        {
          account_t * current = account_list_get_current();
          if( current )
          {
    	if(g_strcasecmp(g_hash_table_lookup( current->properties, "Status"),"REGISTERED")==0)
    	{ 
    	  // OK, everything alright - the call is made with the current account
    	  c -> accountID = current -> accountID;
    	  status_bar_display_account(c);
    	  dbus_place_call(c);
    	}
    	else
    	{
    	  // Current account is not registered 
    	  // So we place a call with the first registered account
    	  // And we switch the current account
    	  current = account_list_get_by_state( ACCOUNT_STATE_REGISTERED );
    	  c -> accountID = current -> accountID;
    	  dbus_place_call(c);
    	  notify_current_account( current );
    	  status_bar_display_account(c);
    	  account_list_set_current_id( c-> accountID );
    	}
          }
          else
          {
    	// No current accounts have been setup. 
    	// So we place a call with the first registered account
    	// and we change the current account
    	current = account_list_get_by_state( ACCOUNT_STATE_REGISTERED );
    	c -> accountID = current -> accountID;
    	dbus_place_call(c);
    	notify_current_account( current );
    	status_bar_display_account(c);
    	account_list_set_current_id( c-> accountID );
          }
        }
    	// Update history
    	c->history_state = OUTGOING;
    	call_list_add(history, c);
      }
    }
    
    /* Internal to action - set the __CURRENT_ACCOUNT variable */
    void
    sflphone_set_current_account()
    {
      if( account_list_get_size() > 0 )
        account_list_set_current_pos( 0 );	
    }
    
    
    /* Internal to action - get the codec list */
    void	
    sflphone_fill_codec_list()
    {
    
      codec_list_clear();
        
      gchar** codecs = (gchar**)dbus_codec_list();
      gchar** order = (gchar**)dbus_get_active_codec_list();
      gchar** details;
      gchar** pl;
    
      for(pl=order; *order; order++)
      {
        codec_t * c = g_new0(codec_t, 1);
        c->_payload = atoi(*order);
        details = (gchar **)dbus_codec_details(c->_payload);
        //printf("Codec details: %s / %s / %s / %s\n",details[0],details[1],details[2],details[3]);
        c->name = details[0];
        c->is_active = TRUE;
        c->sample_rate = atoi(details[1]);
        c->_bitrate = atof(details[2]);
        c->_bandwidth = atof(details[3]);
        codec_list_add(c);
      }
     
      for(pl=codecs; *codecs; codecs++)
      {
        details = (gchar **)dbus_codec_details(atoi(*codecs));
        if(codec_list_get(details[0])!=NULL){
          // does nothing - the codec is already in the list, so is active.
        }
        else{
          codec_t* c = g_new0(codec_t, 1);
          c->_payload = atoi(*codecs);
          c->name = details[0];
          c->is_active = FALSE;
          c->sample_rate = atoi(details[1]);
          c->_bitrate = atof(details[2]);
          c->_bandwidth = atof(details[3]);
          codec_list_add(c);
        }
      }
      if( codec_list_get_size() == 0) {
        
        gchar* markup = g_markup_printf_escaped(_("<b>Error: No audio codecs found.\n\n</b> SFL audio codecs have to be placed in <i>%s</i> or in the <b>.sflphone</b> directory in your home( <i>%s</i> )") , CODECS_DIR , g_get_home_dir());
        main_window_error_message( markup );
        dbus_unregister(getpid());
        exit(0);
      }
    }