Ticket #3293: FrontendAutoDiscovery2.diff

File FrontendAutoDiscovery2.diff, 43.3 KB (added by stuartm, 17 years ago)

Added lirc support and improved dialogs (Updated)

  • libs/libmyth/mythcontext.cpp

     
    194194    MythContextPrivate(MythContext *lparent);
    195195   ~MythContextPrivate();
    196196
    197     bool Init(bool gui);
     197    bool Init(bool gui, DatabaseParams *pParams = NULL );
    198198    bool IsWideMode() const {return (m_baseWidth == 1280);}
    199199    void SetWideMode() {m_baseWidth = 1280; m_baseHeight = 720;}
    200200    bool IsSquareMode() const {return (m_baseWidth == 800);}
     
    204204    void StoreGUIsettings(void);
    205205
    206206    void LoadLogSettings(void);
    207     bool LoadDatabaseSettings(bool reload);
     207    bool LoadDatabaseSettings(bool reload, DatabaseParams *pParams = NULL);
    208208   
    209209    bool FixSettingsFile(void);
    210210    bool WriteSettingsFile(const DatabaseParams &params,
     
    407407    }
    408408}
    409409
    410 bool MythContextPrivate::Init(bool gui)
     410bool MythContextPrivate::Init(bool gui, DatabaseParams *pParams)
    411411{
    412412    m_gui = gui;
    413413
     
    419419
    420420    // Attempts to read DB info from "mysql.txt" from the
    421421    // filesystem, or create it if it does not exist.
    422     if (!LoadDatabaseSettings(false))
     422    if (!LoadDatabaseSettings(false, pParams ))
    423423        return false;
    424424
    425425    // Queries the user for the DB info, using the command
     
    539539    m_logprintlevel = parent->GetNumSetting("LogPrintLevel", LP_ERROR);
    540540}
    541541
    542 bool MythContextPrivate::LoadDatabaseSettings(bool reload)
     542bool MythContextPrivate::LoadDatabaseSettings(bool reload, DatabaseParams *pParams)
    543543{
    544544    if (reload)
    545545    {
     
    547547            delete m_settings;
    548548        m_settings = new Settings;
    549549    }
    550    
     550
     551    // Always load settings first from mysql.txt so LocalHostName can be used.
     552
    551553    if (!parent->LoadSettingsFiles("mysql.txt"))
    552554    {
    553555        VERBOSE(VB_IMPORTANT, "Unable to read configuration file mysql.txt");
     
    557559            parent->LoadSettingsFiles("mysql.txt");
    558560    }
    559561
     562    // Overlay mysql.txt settings if we were passed a DatabaseParams
     563
     564    if (pParams != NULL)
     565    {
     566        m_settings->SetSetting( "DBHostName"             , pParams->dbHostName  );
     567        m_settings->SetSetting( "DBPort"                 , pParams->dbPort      );
     568        m_settings->SetSetting( "DBUserName"             , pParams->dbUserName  );
     569        m_settings->SetSetting( "DBPassword"             , pParams->dbPassword  );
     570        m_settings->SetSetting( "DBName"                 , pParams->dbName      );
     571        m_settings->SetSetting( "DBType"                 , pParams->dbType      );
     572      //m_settings->SetSetting( "wolEnabled"             , pParams->wolEnabled  );
     573        m_settings->SetSetting( "WOLsqlReconnectWaitTime", pParams->wolReconnect);
     574        m_settings->SetSetting( "WOLsqlConnectRetry"     , pParams->wolRetry    );
     575        m_settings->SetSetting( "WOLsqlCommand"          , pParams->wolCommand  );
     576    }
     577
    560578    // Even if we have loaded the settings file, it may be incomplete,
    561579    // so we check for missing values and warn user
    562580    FindSettingsProbs();
     
    824842    : QObject(), d(NULL), app_binary_version(binversion)
    825843{
    826844    qInitNetworkProtocols();
     845
     846    d = new MythContextPrivate(this);
    827847}
    828848
    829 bool MythContext::Init(bool gui)
     849bool MythContext::Init(bool gui, DatabaseParams *pParams )
    830850{
    831851    if (app_binary_version != MYTH_BINARY_VERSION)
    832852    {
     
    839859        return false;
    840860    }
    841861
    842     d = new MythContextPrivate(this);
    843 
    844     if (!d->Init(gui))
     862    if (!d->Init(gui, pParams))
    845863        return false;
    846864
    847865    ActivateSettingsCache(true);
     
    24412459    d->overriddenSettings[key] = value;
    24422460}
    24432461
    2444 
    24452462bool MythContext::SendReceiveStringList(QStringList &strlist, bool quickTimeout, bool block)
    24462463{
    24472464    d->serverSockLock.lock();
  • libs/libmyth/mythcontext.h

     
    243243    MythContext(const QString &binversion);
    244244    virtual ~MythContext();
    245245
    246     bool Init(bool gui = true);
     246    bool Init(bool gui = true, DatabaseParams *pParams = NULL );
    247247
    248248    QString GetMasterHostPrefix(void);
    249249
  • programs/mythfrontend/masterselection.cpp

     
     1//////////////////////////////////////////////////////////////////////////////
     2// Program Name: masterselection.cpp
     3//
     4// Purpose - Classes to Prompt user for MasterBackend
     5//
     6// Created By  : David Blain                    Created On : Jan. 25, 2007
     7// Modified By : Stuart Morgan                  Modified On: 4th July, 2007
     8//
     9//////////////////////////////////////////////////////////////////////////////
     10
     11#include "masterselection.h"
     12#include "upnp.h"
     13#include "mythxmlclient.h"
     14
     15#include <qapplication.h>
     16#include <qinputdialog.h>
     17#include <qlineedit.h>
     18#include <qlabel.h>
     19#include <qfont.h>
     20#include <qdir.h>
     21#include <qstring.h>
     22
     23#include <pthread.h>
     24
     25#include "lirc.h"
     26#include "lircevent.h"
     27
     28static QString GetConfDir(void)
     29{
     30    char *tmp_confdir = getenv("MYTHCONFDIR");
     31    QString dir;
     32    if (tmp_confdir)
     33    {
     34        dir = QString(tmp_confdir);
     35        dir.replace("$HOME", QDir::homeDirPath());
     36    }
     37    else
     38        dir = QDir::homeDirPath() + "/.mythtv";
     39
     40    return dir;
     41}
     42
     43static void *SpawnLirc(void *param)
     44{
     45    QString config_file = GetConfDir() + "/lircrc";
     46    if (!QFile::exists(config_file))
     47        config_file = QDir::homeDirPath() + "/.lircrc";
     48
     49    VERBOSE(VB_GENERAL, QString("Spawning Lirc: %1").arg(config_file));
     50
     51    LircClient *cl = new LircClient((MasterSelectionWindow *)param);
     52    if (!cl->Init(config_file, "mythtv"))
     53        cl->Process();
     54
     55    return NULL;
     56}
     57
     58/////////////////////////////////////////////////////////////////////////////
     59// return values:   -1 = Exit Application
     60//                   0 = Continue with no Connection Infomation
     61//                   1 = Connection Information found
     62/////////////////////////////////////////////////////////////////////////////
     63
     64int MasterSelection::GetConnectionInfo( MediaRenderer  *pUPnp,
     65                                        DatabaseParams *pParams,
     66                                        bool            bPromptForBackend )
     67{
     68    if ((pUPnp == NULL) || (pParams == NULL))
     69    {
     70        VERBOSE( VB_UPNP, "MasterSelectionDialog::GetConnectionInfo - "
     71                          "Invalid NULL parameters." );
     72        return -1;
     73    }
     74
     75    // ----------------------------------------------------------------------
     76    // Try to get the last selected (default) Master
     77    // ----------------------------------------------------------------------
     78
     79    int                    nRetCode         = -1;
     80    bool                   bExitLoop        = false;
     81    bool                   bTryConnectAgain = false;
     82    QString                sPin             = "";
     83    MasterSelectionWindow *pMasterWindow    = NULL;
     84    DeviceLocation        *pDeviceLoc       = NULL;
     85
     86    if (!bPromptForBackend)
     87        pDeviceLoc = pUPnp->GetDefaultMaster();
     88
     89    if (pDeviceLoc != NULL)
     90        sPin = pDeviceLoc->m_sSecurityPin;
     91
     92    // ----------------------------------------------------------------------
     93    // Loop until we have a valid DatabaseParams, or the user cancels
     94    // ----------------------------------------------------------------------
     95
     96    while (!bExitLoop)
     97    {
     98        bTryConnectAgain = false;
     99
     100        if (pDeviceLoc == NULL)
     101        {
     102            if ( pMasterWindow == NULL)
     103            {
     104                pMasterWindow = new MasterSelectionWindow();
     105                pMasterWindow->show();
     106            }
     107
     108            MasterSelectionDialog selectionDlg( pMasterWindow );
     109
     110            // --------------------------------------------------------------
     111            // Show dialog and check for Cancel.
     112            // --------------------------------------------------------------
     113
     114            if ( !selectionDlg.exec() )
     115            {
     116                nRetCode  = -1;
     117                bExitLoop = true;
     118            }
     119            else
     120            {
     121                // ----------------------------------------------------------
     122                // Did user select "No Backend"
     123                // ----------------------------------------------------------
     124
     125                sPin = "";
     126
     127                if (( pDeviceLoc = selectionDlg.GetSelectedDevice()) == NULL)
     128                {
     129                    nRetCode  = 0;
     130                    bExitLoop = true;
     131                }
     132            }
     133        }
     134
     135        // ------------------------------------------------------------------
     136        // If DeviceLoc != NULL... Try and retrieve ConnectionInformation
     137        // ------------------------------------------------------------------
     138
     139        if (pDeviceLoc != NULL)
     140        {
     141            MythXMLClient mythXml( pDeviceLoc->m_sLocation );
     142
     143            UPnPResultCode eCode = mythXml.GetConnectionInfo( sPin, pParams );
     144
     145            switch( eCode )
     146            {
     147                case UPnPResult_Success:
     148                {
     149                    VERBOSE(VB_GENERAL, QString("Database Hostname: %1")
     150                                        .arg(pParams->dbHostName));
     151
     152                    pUPnp->SetDefaultMaster( pDeviceLoc, sPin );
     153
     154                    bExitLoop = true;
     155                    nRetCode  = 1;
     156
     157                    break;
     158                }
     159
     160                case UPnPResult_ActionNotAuthorized:
     161                {
     162                    if ( pMasterWindow == NULL)
     163                    {
     164                        pMasterWindow = new MasterSelectionWindow();
     165                        pMasterWindow->show();
     166                    }
     167
     168                    // Prompt For Pin and try again...
     169
     170                    VERBOSE( VB_IMPORTANT, QString( "Access Denied for %1" )
     171                               .arg( pDeviceLoc->GetFriendlyName( true ) ));
     172
     173                    PinDialog *passwordDlg = new PinDialog(pMasterWindow,
     174                                         pDeviceLoc->GetFriendlyName( true ));
     175
     176                    if ( passwordDlg->exec() == QDialog::Accepted )
     177                    {
     178                        sPin = passwordDlg->GetPin();
     179                        bTryConnectAgain = true;
     180                    }
     181
     182                    delete passwordDlg;
     183
     184                    break;
     185                }
     186
     187                default:
     188                {
     189                    if ( pMasterWindow == NULL)
     190                    {
     191                        pMasterWindow = new MasterSelectionWindow();
     192                        pMasterWindow->show();
     193                    }
     194
     195                    // Display Error Msg and have user select different Master.
     196
     197                    VERBOSE( VB_IMPORTANT, QString( "Error Retrieving "
     198                                    "ConnectionInfomation for %1 (%2) %3" )
     199                                    .arg( pDeviceLoc->GetFriendlyName( true ) )
     200                                    .arg( eCode )
     201                                    .arg( UPnp::GetResultDesc( eCode )));
     202
     203
     204                    QMessageBox msgBox( "Error",
     205                                        QString( "(%1) - %2" )
     206                                           .arg( eCode )
     207                                           .arg( UPnp::GetResultDesc( eCode )),
     208                                        QMessageBox::Critical,
     209                                        QMessageBox::Ok,
     210                                        QMessageBox::NoButton,
     211                                        QMessageBox::NoButton,
     212                                        pMasterWindow,
     213                                        NULL,
     214                                        TRUE,
     215                                        Qt::WStyle_Customize | Qt::WStyle_NoBorder );
     216
     217                    msgBox.exec();
     218                    break;
     219                }
     220            }
     221
     222            if ( !bTryConnectAgain )
     223            {
     224                pDeviceLoc->Release();
     225                pDeviceLoc = NULL;
     226            }
     227        }
     228    }
     229
     230    if ( pMasterWindow != NULL)
     231    {
     232        pMasterWindow->hide();
     233        delete pMasterWindow;
     234    }
     235
     236    return nRetCode;
     237}
     238
     239/////////////////////////////////////////////////////////////////////////////
     240//
     241/////////////////////////////////////////////////////////////////////////////
     242
     243MasterSelectionWindow::MasterSelectionWindow()
     244    : QWidget( NULL, "BackgroundWindow" )
     245{
     246    QDesktopWidget *pDesktop = QApplication::desktop();
     247
     248    int nScreenHeight = pDesktop->height();
     249
     250    float fhMulti = nScreenHeight / (float)600;
     251
     252    QFont font = QFont("Arial");
     253
     254    if (!font.exactMatch())
     255        font = QFont();
     256
     257    font.setStyleHint( QFont::SansSerif, QFont::PreferAntialias );
     258    font.setPointSize((int)floor(14 * fhMulti ));
     259
     260    QColorGroup colors( QColor( 255, 255, 255 ),    // Foreground
     261                        QColor(   0,  64, 128 ),    // background
     262                        QColor( 196, 196, 196 ),    // light
     263                        QColor(  64,  64,  64 ),    // dark
     264                        QColor( 128, 128, 128 ),    // mid
     265                        QColor( 255, 255, 255 ),    // text
     266                        QColor(   0, 100, 192 ));   // Base
     267
     268    QApplication::setFont   ( font, TRUE );
     269    QApplication::setPalette( QPalette( colors, colors, colors ), TRUE );
     270
     271    showFullScreen();
     272
     273    pthread_t lirc_tid;
     274    pthread_attr_t attr;
     275    pthread_attr_init(&attr);
     276    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
     277    pthread_create(&lirc_tid, &attr, SpawnLirc, this);
     278    pthread_attr_destroy(&attr);
     279
     280}
     281
     282void MasterSelectionWindow::customEvent(QCustomEvent *e)
     283{
     284
     285    if (e->type() == kLircKeycodeEventType)
     286    {
     287        LircKeycodeEvent *lke = (LircKeycodeEvent *)e;
     288        int keycode = lke->getKeycode();
     289
     290        if (keycode)
     291        {
     292            switch (keycode)
     293            {
     294                case Qt::Key_Left :
     295                {
     296                    keycode = Qt::Key_BackTab;
     297                    break;
     298                }
     299                case Qt::Key_Right :
     300                {
     301                    keycode = Qt::Key_Tab;
     302                    break;
     303                }
     304                default:
     305                    break;
     306            }
     307
     308            int mod = keycode & MODIFIER_MASK;
     309            int k = keycode & ~MODIFIER_MASK; /* trim off the mod */
     310            int ascii = 0;
     311            QString text;
     312
     313            if (k & UNICODE_ACCEL)
     314            {
     315                QChar c(k & ~UNICODE_ACCEL);
     316                ascii = c.latin1();
     317                text = QString(c);
     318            }
     319
     320            mod = ((mod & Qt::CTRL) ? Qt::ControlButton : 0) |
     321                ((mod & Qt::META) ? Qt::MetaButton : 0) |
     322                ((mod & Qt::ALT) ? Qt::AltButton : 0) |
     323                ((mod & Qt::SHIFT) ? Qt::ShiftButton : 0);
     324
     325            QKeyEvent key(lke->isKeyDown() ? QEvent::KeyPress :
     326                        QEvent::KeyRelease, k, ascii, mod, text);
     327
     328            QObject *key_target = getTarget();
     329            if (!key_target)
     330                QApplication::sendEvent(this, &key);
     331            else
     332                QApplication::sendEvent(key_target, &key);
     333        }
     334        else
     335        {
     336            VERBOSE(VB_IMPORTANT, QString("LircClient warning: attempt to "
     337                                  "convert '%1' to a key sequence failed. Fix "
     338                                  "your key mappings.")
     339                                  .arg(lke->getLircText()));
     340        }
     341    }
     342
     343}
     344
     345QObject *MasterSelectionWindow::getTarget()
     346{
     347    QObject *key_target = NULL;
     348
     349    key_target = QWidget::keyboardGrabber();
     350
     351    if (!key_target)
     352    {
     353        QWidget *focus_widget = qApp->focusWidget();
     354        if (focus_widget && focus_widget->isEnabled())
     355        {
     356            key_target = focus_widget;
     357        }
     358    }
     359
     360    if (!key_target)
     361        key_target = this;
     362
     363    return key_target;
     364}
     365
     366/////////////////////////////////////////////////////////////////////////////
     367//
     368/////////////////////////////////////////////////////////////////////////////
     369
     370PinDialog::PinDialog( QWidget *pParent, QString name )
     371        : QDialog( pParent, "Pin Entry", TRUE, WType_Popup )
     372{
     373    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
     374
     375    m_pPassword = new QLineEdit( this );
     376    m_pPassword->setEchoMode(QLineEdit::Password);
     377    m_pPassword->setFocus();
     378
     379    m_pCancel  = new QPushButton( tr("Cancel"), this );
     380    m_pOk      = new QPushButton( tr("OK")    , this );
     381
     382    m_pLayout  = new QGridLayout( this, 8, 8, 5 );
     383
     384    m_pLayout->addMultiCellWidget( new QLabel( name, this ), 0, 0, 1, 4 );
     385    m_pLayout->addMultiCellWidget( new QLabel( tr( "Security Pin:" ), this ),
     386                                   3, 3, 1, 4 );
     387    m_pLayout->addMultiCellWidget(m_pPassword, 5, 5, 1, 3);
     388    m_pLayout->addWidget(m_pCancel, 7, 1);
     389    m_pLayout->addWidget(m_pOk, 7, 3);
     390
     391    connect( m_pPassword, SIGNAL( returnPressed() ), SLOT( accept()) );
     392    connect( m_pOk    , SIGNAL( clicked() ), SLOT( accept()) );
     393    connect( m_pCancel, SIGNAL( clicked() ), SLOT( reject()) );
     394}
     395
     396PinDialog::~PinDialog()
     397{
     398
     399}
     400
     401QString PinDialog::GetPin()
     402{
     403    QString pin = m_pPassword->text();
     404
     405    return pin;
     406}
     407
     408/////////////////////////////////////////////////////////////////////////////
     409//
     410/////////////////////////////////////////////////////////////////////////////
     411
     412MasterSelectionDialog::MasterSelectionDialog( MasterSelectionWindow *pParent )
     413       : QDialog( pParent, "Master Mediaserver Selection", TRUE,
     414                  WStyle_Customize | WStyle_NoBorder )
     415{
     416    setFocusPolicy(QWidget::NoFocus);
     417
     418    m_pCancel  = new QPushButton( tr("Cancel"), this );
     419    m_pSearch  = new QPushButton( tr("Search"), this );
     420
     421    m_pListBox = new QListBox( this );
     422    m_pListBox->setFocus();
     423    m_pListBox->setFrameShape( QFrame::WinPanel );
     424    m_pListBox->setSelectionMode( QListBox::Single );
     425
     426    m_pOk      = new QPushButton( tr("OK")    , this );
     427
     428    m_pLayout  = new QGridLayout( this, 7, 5, 6 );
     429
     430    m_pLayout->setMargin( 50 );
     431
     432    m_pLayout->addWidget( m_pSearch, 5, 0 );
     433    m_pLayout->addWidget( m_pCancel, 5, 3 );
     434    m_pLayout->addWidget( m_pOk    , 5, 4 );
     435
     436    QString labeltext = tr( "Select Default Myth Backend Server:" );
     437
     438    m_pLayout->addMultiCellWidget( new QLabel( labeltext, this ), 1, 1, 0, 4 );
     439
     440    m_pLayout->addMultiCellWidget( m_pListBox, 3, 3, 0, 4 );
     441
     442    connect( m_pOk    , SIGNAL( clicked() ), SLOT( accept()) );
     443    connect( m_pCancel, SIGNAL( clicked() ), SLOT( reject()) );
     444    connect( m_pSearch, SIGNAL( clicked() ), SLOT( Search()) );
     445    connect( m_pListBox, SIGNAL( returnPressed(QListBoxItem *) ),
     446            SLOT( accept()) );
     447
     448    showFullScreen();
     449
     450    UPnp::AddListener( this );
     451
     452    QListBoxItem *pItem = AddItem( NULL, tr("Do Not Connect To MythBackend") );
     453
     454    m_pListBox->setCurrentItem( pItem );
     455
     456    Search();
     457    FillListBox();
     458}
     459
     460MasterSelectionDialog::~MasterSelectionDialog()
     461{
     462    UPnp::RemoveListener( this );
     463
     464    for (ItemMap::iterator it  = m_Items.begin();
     465                           it != m_Items.end();
     466                         ++it )
     467    {
     468        ListBoxDevice *pItem = it.data();
     469
     470        if (pItem != NULL)
     471            delete pItem;
     472    }
     473
     474    m_Items.clear();
     475
     476}
     477
     478/////////////////////////////////////////////////////////////////////////////
     479//  Caller MUST call Release on returned pointer
     480/////////////////////////////////////////////////////////////////////////////
     481
     482DeviceLocation *MasterSelectionDialog::GetSelectedDevice( void )
     483{
     484    DeviceLocation *pLoc = NULL;
     485    ListBoxDevice  *pItem = (ListBoxDevice *)m_pListBox->selectedItem();
     486
     487    if (pItem != NULL)
     488    {
     489        if ((pLoc = pItem->m_pLocation) != NULL)
     490            pLoc->AddRef();
     491    }
     492
     493    return pLoc;
     494}
     495
     496ListBoxDevice *MasterSelectionDialog::AddItem( DeviceLocation *pLoc,
     497                                                QString sName )
     498{
     499    ListBoxDevice *pItem = NULL;
     500    QString        sUSN  = "None";
     501
     502    if (pLoc != NULL)
     503        sUSN  = pLoc->m_sUSN;
     504
     505    ItemMap::iterator it = m_Items.find( sUSN );
     506
     507    if ( it == m_Items.end())
     508    {
     509        pItem = new ListBoxDevice( m_pListBox, sName, pLoc );
     510        m_Items.insert( sUSN, pItem );
     511    }
     512    else
     513        pItem = it.data();
     514
     515    return pItem;
     516}
     517
     518void MasterSelectionDialog::RemoveItem( QString sUSN )
     519{
     520    ItemMap::iterator it = m_Items.find( sUSN );
     521
     522    if ( it != m_Items.end() )
     523    {
     524        ListBoxDevice *pItem = it.data();
     525
     526        if (pItem != NULL)
     527            delete pItem;
     528
     529        m_Items.remove( it );
     530    }
     531}
     532
     533void MasterSelectionDialog::Search( void )
     534{
     535    UPnp::PerformSearch( "urn:schemas-mythtv-org:device:MasterMediaServer:1" );
     536}
     537
     538void MasterSelectionDialog::FillListBox( void )
     539{
     540
     541    EntryMap ourMap;
     542
     543    SSDPCacheEntries *pEntries = UPnp::g_SSDPCache.Find(
     544                        "urn:schemas-mythtv-org:device:MasterMediaServer:1" );
     545
     546    if (pEntries != NULL)
     547    {
     548        pEntries->AddRef();
     549        pEntries->Lock();
     550
     551        EntryMap *pMap = pEntries->GetEntryMap();
     552
     553
     554        for (EntryMap::Iterator it  = pMap->begin();
     555                                it != pMap->end();
     556                              ++it )
     557        {
     558            DeviceLocation *pEntry = (DeviceLocation *)it.data();
     559
     560            if (pEntry != NULL)
     561            {
     562                pEntry->AddRef();
     563                ourMap.insert( pEntry->m_sUSN, pEntry );
     564            }
     565        }
     566
     567        pEntries->Unlock();
     568        pEntries->Release();
     569    }
     570
     571    for (EntryMap::Iterator it  = ourMap.begin();
     572                            it != ourMap.end();
     573                          ++it )
     574    {
     575        DeviceLocation *pEntry = (DeviceLocation *)it.data();
     576
     577        if (pEntry != NULL)
     578        {
     579            AddItem( pEntry, pEntry->GetFriendlyName( true ));
     580
     581            pEntry->Release();
     582        }
     583    }
     584}
     585
     586void MasterSelectionDialog::customEvent(QCustomEvent *e)
     587{
     588
     589    if ((MythEvent::Type)(e->type()) == MythEvent::MythEventMessage)
     590    {
     591        MythEvent *me = (MythEvent *)e;
     592        QString message = me->Message();
     593
     594        VERBOSE(VB_UPNP, QString("MasterSelectionDialog::customEvent - %1 : "
     595                                 "%2 - %3").arg(message)
     596                                 .arg(me->ExtraData( 0 ))
     597                                 .arg(me->ExtraData( 1 )));
     598
     599        if (message.startsWith( "SSDP_ADD" ))
     600        {
     601            QString sURI = me->ExtraData( 0 );
     602            QString sURN = me->ExtraData( 1 );
     603            QString sURL = me->ExtraData( 2 );
     604
     605            if ( sURI.startsWith( "urn:schemas-mythtv-org:device:MasterMediaServer:" ))
     606            {
     607                DeviceLocation *pLoc    = UPnp::g_SSDPCache.Find( sURI, sURN );
     608
     609                if (pLoc != NULL)
     610                {
     611                    pLoc->AddRef();
     612
     613                    AddItem( pLoc, pLoc->GetFriendlyName( true ));
     614
     615                    pLoc->Release();
     616                }
     617            }
     618        }
     619        else if (message.startsWith( "SSDP_REMOVE" ))
     620        {
     621            //-=>Note: This code will never get executed until
     622            //         SSDPCache is changed to handle NotifyRemove correctly
     623
     624            QString sURI = me->ExtraData( 0 );
     625            QString sURN = me->ExtraData( 1 );
     626
     627            RemoveItem( sURN );
     628        }
     629    }
     630}
  • programs/mythfrontend/mediarenderer.cpp

    Property changes on: programs/mythfrontend/masterselection.cpp
    ___________________________________________________________________
    Name: svn:eol-style
       + native
    
     
     1/////////////////////////////////////////////////////////////////////////////
     2// Program Name: mediarenderer.cpp
     3//                                                                           
     4// Purpose - uPnp Media Renderer main Class
     5//                                                                           
     6// Created By  : David Blain                    Created On : Jan. 15, 2007
     7// Modified By :                                Modified On:                 
     8//                                                                           
     9/////////////////////////////////////////////////////////////////////////////
     10
     11#include "mediarenderer.h"
     12
     13/////////////////////////////////////////////////////////////////////////////
     14/////////////////////////////////////////////////////////////////////////////
     15//
     16// UPnp MediaRenderer Class implementaion
     17//
     18/////////////////////////////////////////////////////////////////////////////
     19/////////////////////////////////////////////////////////////////////////////
     20
     21/////////////////////////////////////////////////////////////////////////////
     22//
     23/////////////////////////////////////////////////////////////////////////////
     24
     25MediaRenderer::MediaRenderer()
     26{
     27    VERBOSE(VB_UPNP, "MediaRenderer::Begin" );
     28
     29    // ----------------------------------------------------------------------
     30    // Initialize Configuration class (XML file for frontend)
     31    // ----------------------------------------------------------------------
     32
     33    SetConfiguration( new XmlConfiguration( "config.xml" ));
     34
     35    // ----------------------------------------------------------------------
     36    // Create mini HTTP Server
     37    // ----------------------------------------------------------------------
     38
     39    int nPort = g_pConfig->GetValue( "UPnP/MythFrontend/ServicePort", 6547 );
     40
     41    m_pHttpServer = new HttpServer( nPort );
     42
     43    if (!m_pHttpServer->ok())
     44    {
     45        VERBOSE(VB_IMPORTANT, "MediaRenderer::HttpServer Create Error");
     46        // exit(BACKEND_BUGGY_EXIT_NO_BIND_STATUS);
     47        return;
     48    }
     49
     50    // ----------------------------------------------------------------------
     51    // Initialize UPnp Stack
     52    // ----------------------------------------------------------------------
     53
     54    if (Initialize( nPort, m_pHttpServer ))
     55    {
     56        // ------------------------------------------------------------------
     57        // Create device Description
     58        // ------------------------------------------------------------------
     59
     60        VERBOSE(VB_UPNP, QString( "MediaRenderer::Creating UPnp Description" ));
     61
     62        UPnpDevice &device = g_UPnpDeviceDesc.m_rootDevice;
     63
     64        device.m_sDeviceType        = "urn:schemas-upnp-org:device:MediaRenderer:1";
     65        device.m_sFriendlyName      = "MythTv AV Renderer";
     66        device.m_sManufacturer      = "MythTV";
     67        device.m_sManufacturerURL   = "http://www.mythtv.org";
     68        device.m_sModelDescription  = "MythTV AV Media Renderer";
     69        device.m_sModelName         = "MythTV AV Media Renderer";
     70        device.m_sModelURL          = "http://www.mythtv.org";
     71        device.m_sUPC               = "";
     72        device.m_sPresentationURL   = "";
     73
     74        // ------------------------------------------------------------------
     75        // Register any HttpServerExtensions...
     76        // ------------------------------------------------------------------
     77
     78        QString sSinkProtocols = "http-get:*:image/gif:*,"
     79                                 "http-get:*:image/jpeg:*,"
     80                                 "http-get:*:image/png:*,"
     81                                 "http-get:*:video/avi:*,"
     82                                 "http-get:*:audio/mpeg:*,"
     83                                 "http-get:*:audio/wav:*,"
     84                                 "http-get:*:video/mpeg:*,"
     85                                 "http-get:*:video/nupplevideo:*,"
     86                                 "http-get:*:video/x-ms-wmv:*";
     87
     88        // VERBOSE(VB_UPNP, QString( "MediaRenderer::Registering AVTransport Service." ));
     89        // m_pHttpServer->RegisterExtension( m_pUPnpAVT = new UPnpAVTransport( RootDevice() ));
     90
     91        VERBOSE(VB_UPNP, QString( "MediaRenderer::Registering CMGR Service." ));
     92        m_pHttpServer->RegisterExtension( m_pUPnpCMGR= new UPnpCMGR( RootDevice(), "", sSinkProtocols ));
     93
     94        // VERBOSE(VB_UPNP, QString( "MediaRenderer::Registering RenderingControl Service." ));
     95        // m_pHttpServer->RegisterExtension( m_pUPnpRCTL= new UPnpRCTL( RootDevice() ));
     96
     97        Start();
     98
     99    }
     100    else
     101    {
     102        VERBOSE(VB_IMPORTANT, "MediaRenderer::Unable to Initialize UPnp Stack");
     103        // exit(BACKEND_BUGGY_EXIT_NO_BIND_STATUS);
     104    }
     105
     106
     107
     108    VERBOSE(VB_UPNP, QString( "MediaRenderer::End" ));
     109}
     110
     111/////////////////////////////////////////////////////////////////////////////
     112//
     113/////////////////////////////////////////////////////////////////////////////
     114
     115MediaRenderer::~MediaRenderer()
     116{
     117    if (m_pHttpServer)
     118        delete m_pHttpServer;
     119}
     120
     121/////////////////////////////////////////////////////////////////////////////
     122// Caller MUST call Release on returned pointer
     123/////////////////////////////////////////////////////////////////////////////
     124
     125DeviceLocation *MediaRenderer::GetDefaultMaster()
     126{
     127    UPnp::PerformSearch( "urn:schemas-mythtv-org:device:MasterMediaServer:1" );
     128
     129    QString sUSN = g_pConfig->GetValue( "UPnP/MythFrontend/DefaultBackend/USN"        , "" );
     130    QString sPin = g_pConfig->GetValue( "UPnP/MythFrontend/DefaultBackend/SecurityPin", "" );
     131
     132    if (sUSN.isEmpty())
     133        return NULL;
     134
     135    DeviceLocation *pDeviceLoc = NULL;
     136
     137    // Lets wait up to 2 seconds for the backend to answer our Search request;
     138
     139    QTime timer;
     140    timer.start();
     141
     142    while (timer.elapsed() < 2000 )
     143    {
     144       pDeviceLoc = UPnp::g_SSDPCache.Find( "urn:schemas-mythtv-org:device:MasterMediaServer:1",
     145                                            sUSN );
     146
     147        if ( pDeviceLoc != NULL)
     148        {
     149            pDeviceLoc->AddRef();
     150
     151            pDeviceLoc->m_sSecurityPin = sPin;
     152
     153            return pDeviceLoc;
     154        }
     155
     156       usleep(10000);
     157    }
     158
     159    return NULL;
     160}
     161
     162/////////////////////////////////////////////////////////////////////////////
     163//
     164/////////////////////////////////////////////////////////////////////////////
     165
     166void MediaRenderer::SetDefaultMaster( DeviceLocation *pDeviceLoc, const QString &sPin )
     167{
     168    if ( pDeviceLoc != NULL)
     169    {
     170        pDeviceLoc->m_sSecurityPin = sPin;
     171
     172        g_pConfig->SetValue( "UPnP/MythFrontend/DefaultBackend/USN"        , pDeviceLoc->m_sUSN );
     173        g_pConfig->SetValue( "UPnP/MythFrontend/DefaultBackend/SecurityPin", sPin );
     174        g_pConfig->Save();
     175    }
     176}
  • programs/mythfrontend/main.cpp

    Property changes on: programs/mythfrontend/mediarenderer.cpp
    ___________________________________________________________________
    Name: svn:eol-style
       + native
    
     
    5050
    5151#include "libmythui/myththemedmenu.h"
    5252#include "libmythui/myththemebase.h"
     53#include "mediarenderer.h"
     54#include "masterselection.h"
    5355
    5456#define NO_EXIT  0
    5557#define QUIT     1
     
    5961static MythThemeBase *themeBase;
    6062XBox *xbox = NULL;
    6163
     64MediaRenderer   *g_pUPnp       = NULL;
     65
    6266void startGuide(void)
    6367{
    6468    uint chanid = 0;
     
    769773
    770774int main(int argc, char **argv)
    771775{
     776    bool bPromptForBackend = false;
    772777
    773778    QString geometry = QString::null;
    774779    QString display  = QString::null;
     
    842847                return FRONTEND_EXIT_INVALID_CMDLINE;
    843848            }
    844849        }
     850        else if (!strcmp(a.argv()[argpos],"--prompt") ||
     851                 !strcmp(a.argv()[argpos],"-p" ))
     852        {
     853            bPromptForBackend = true;
     854        }
    845855    }
    846856
    847857    if (!display.isEmpty())
     
    850860    }
    851861
    852862    gContext = new MythContext(MYTH_BINARY_VERSION);
    853     if (!gContext->Init())
    854     {   
     863    g_pUPnp  = new MediaRenderer();
     864
     865    DatabaseParams *pParams = new DatabaseParams;
     866
     867    int nRetCode = MasterSelection::GetConnectionInfo( g_pUPnp,
     868                                                       pParams,
     869                                                       bPromptForBackend );
     870    switch( nRetCode )
     871    {
     872        case -1:    // Exit Application
     873            return FRONTEND_EXIT_OK;
     874
     875        case  0:    // Continue with no Connection Infomation
     876        {
     877            delete pParams;
     878            pParams = NULL;
     879
     880            break;
     881        }
     882
     883        case 1:     // Connection Information found
     884        default:
     885            break;
     886    }
     887
     888    if (!gContext->Init( true, pParams ))
     889    {
    855890        VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting.");
    856891        return FRONTEND_EXIT_NO_MYTHCONTEXT;
    857892    }
    858893
     894    if (pParams != NULL)
     895    {
     896        delete pParams;
     897        pParams = NULL;
     898    }
     899
    859900    for(int argpos = 1; argpos < a.argc(); ++argpos)
    860901    {
    861902        if (!strcmp(a.argv()[argpos],"-l") ||
     
    9911032                return FRONTEND_EXIT_INVALID_CMDLINE;
    9921033            }
    9931034        }
     1035        else if (!strcmp(a.argv()[argpos],"--prompt") ||
     1036                 !strcmp(a.argv()[argpos],"-p" ))
     1037        {
     1038        }
    9941039        else if ((argpos + 1 == a.argc()) &&
    9951040                    !QString(a.argv()[argpos]).startsWith("-"))
    9961041        {
     
    10191064                    "  --get-setting KEY[,KEY2,etc] Returns the current database setting for 'KEY'" << endl <<
    10201065                    "                               Use a comma seperated list to return multiple values" << endl <<
    10211066                    "-v or --verbose debug-level    Use '-v help' for level info" << endl <<
     1067                    "-p or --prompt                 Always prompt for Mythbackend selection." << endl <<
    10221068
    10231069                    "--version                      Version information" << endl <<
    10241070                    "<plugin>                       Initialize and run this plugin" << endl <<
     
    12731319    DestroyMythMainWindow();
    12741320    delete themeBase;
    12751321    delete gContext;
     1322    delete g_pUPnp;
     1323
    12761324    return FRONTEND_EXIT_OK;
    12771325}
    12781326
  • programs/mythfrontend/mythfrontend.pro

     
    2626HEADERS += manualbox.h playbackbox.h viewscheduled.h globalsettings.h
    2727HEADERS += manualschedule.h programrecpriority.h channelrecpriority.h
    2828HEADERS += statusbox.h networkcontrol.h custompriority.h
     29HEADERS += mediarenderer.h masterselection.h
    2930
    3031SOURCES += main.cpp manualbox.cpp playbackbox.cpp viewscheduled.cpp
    3132SOURCES += globalsettings.cpp manualschedule.cpp programrecpriority.cpp
    3233SOURCES += channelrecpriority.cpp statusbox.cpp networkcontrol.cpp
     34SOURCES += mediarenderer.cpp masterselection.cpp
    3335SOURCES += custompriority.cpp
    3436
    3537macx {
  • programs/mythfrontend/masterselection.h

     
     1//////////////////////////////////////////////////////////////////////////////
     2// Program Name: masterselection.h
     3//
     4// Purpose - Classes to Prompt user for MasterBackend
     5//
     6// Created By  : David Blain                    Created On : Jan. 25, 2007
     7// Modified By : Stuart Morgan                  Modified On: 4th July, 2007
     8//
     9//////////////////////////////////////////////////////////////////////////////
     10
     11#include <qdialog.h>
     12#include <qpushbutton.h>
     13#include <qlayout.h>
     14#include <qlistbox.h>
     15#include <qlineedit.h>
     16#include <qmessagebox.h>
     17#include <qmap.h>
     18#include <math.h>
     19
     20#include "libmythupnp/upnpdevice.h"
     21#include "mediarenderer.h"
     22
     23#ifndef __MASTERSELECTION_H__
     24#define __MASTERSELECTION_H__
     25
     26/////////////////////////////////////////////////////////////////////////////
     27//
     28/////////////////////////////////////////////////////////////////////////////
     29
     30class MasterSelection
     31{
     32    public:
     33
     34        static int GetConnectionInfo( MediaRenderer  *pUPnp,
     35                                      DatabaseParams *pParams,
     36                                      bool            bPromptForBackend );
     37};
     38
     39/////////////////////////////////////////////////////////////////////////////
     40//
     41/////////////////////////////////////////////////////////////////////////////
     42
     43class ListBoxDevice : public QListBoxText
     44{
     45    public:
     46
     47        DeviceLocation *m_pLocation;
     48
     49        ListBoxDevice( QListBox *pList, const QString &sName, DeviceLocation *pLoc )
     50            : QListBoxText( pList, sName )
     51        {
     52            if ((m_pLocation = pLoc) != NULL)
     53                m_pLocation->AddRef();
     54        }
     55
     56        virtual ~ListBoxDevice()
     57        {
     58            if ( m_pLocation != NULL)
     59                m_pLocation->Release();
     60        }
     61};
     62
     63typedef QMap< QString, ListBoxDevice *>  ItemMap;
     64
     65/////////////////////////////////////////////////////////////////////////////
     66//
     67/////////////////////////////////////////////////////////////////////////////
     68
     69class MasterSelectionWindow : public QWidget
     70{
     71    public:
     72
     73        MasterSelectionWindow();
     74
     75    protected:
     76
     77        void customEvent(QCustomEvent *e);
     78        QObject *getTarget();
     79
     80};
     81
     82/////////////////////////////////////////////////////////////////////////////
     83//
     84/////////////////////////////////////////////////////////////////////////////
     85
     86class MasterSelectionDialog : public QDialog
     87{
     88    Q_OBJECT
     89
     90    protected:
     91
     92        ItemMap          m_Items;
     93
     94        QGridLayout     *m_pLayout;
     95        QListBox        *m_pListBox;
     96
     97        QPushButton     *m_pOk;
     98        QPushButton     *m_pCancel;
     99        QPushButton     *m_pSearch;
     100
     101        ListBoxDevice *AddItem   ( DeviceLocation *pLoc, QString sName );
     102        void           RemoveItem( QString sURN );
     103
     104    public slots:
     105
     106        void Search     ( void );
     107        void FillListBox( void );
     108
     109    public:
     110
     111                 MasterSelectionDialog( MasterSelectionWindow *pParent );
     112        virtual ~MasterSelectionDialog();
     113
     114        void     customEvent(QCustomEvent *e);
     115
     116        DeviceLocation *GetSelectedDevice( void );
     117
     118
     119};
     120
     121/////////////////////////////////////////////////////////////////////////////
     122//
     123/////////////////////////////////////////////////////////////////////////////
     124
     125class PinDialog : public QDialog
     126{
     127    Q_OBJECT
     128
     129    public:
     130
     131                 PinDialog( QWidget *pParent, QString name );
     132        virtual ~PinDialog();
     133
     134        QString  GetPin();
     135
     136    protected:
     137
     138        QGridLayout     *m_pLayout;
     139        QListBox        *m_pListBox;
     140
     141        QPushButton     *m_pOk;
     142        QPushButton     *m_pCancel;
     143
     144        QLineEdit       *m_pPassword;
     145
     146};
     147
     148#endif
  • programs/mythfrontend/mediarenderer.h

    Property changes on: programs/mythfrontend/masterselection.h
    ___________________________________________________________________
    Name: svn:eol-style
       + native
    
     
     1//////////////////////////////////////////////////////////////////////////////
     2// Program Name: mediarenderer.h
     3//                                                                           
     4// Purpose - uPnp Media Renderer main Class
     5//                                                                           
     6// Created By  : David Blain                    Created On : Jan. 25, 2007
     7// Modified By :                                Modified On:                 
     8//                                                                           
     9//////////////////////////////////////////////////////////////////////////////
     10
     11#ifndef __MEDIARENDERER_H__
     12#define __MEDIARENDERER_H__
     13
     14#include <qobject.h>
     15#include <qmutex.h>
     16
     17#include "libmythupnp/upnp.h"
     18#include "libmythupnp/upnpcmgr.h"
     19#include "libmythupnp/mythxmlclient.h"
     20
     21//////////////////////////////////////////////////////////////////////////////
     22//////////////////////////////////////////////////////////////////////////////
     23//
     24//
     25//
     26//////////////////////////////////////////////////////////////////////////////
     27//////////////////////////////////////////////////////////////////////////////
     28
     29class MediaRenderer : public UPnp
     30{
     31    private:
     32
     33        HttpServer      *m_pHttpServer;
     34
     35    protected:
     36
     37//        UPnpControl            *m_pUPnpControl;      // Do not delete (auto deleted)
     38        UPnpCMGR               *m_pUPnpCMGR;     // Do not delete (auto deleted)
     39
     40    public:
     41                 MediaRenderer();
     42        virtual ~MediaRenderer();
     43
     44        DeviceLocation *GetDefaultMaster();
     45        void            SetDefaultMaster( DeviceLocation *pDeviceLoc, const QString &sPin );
     46
     47};
     48
     49#endif
  • programs/mythtv-setup/backendsettings.cpp

    Property changes on: programs/mythfrontend/mediarenderer.h
    ___________________________________________________________________
    Name: svn:eol-style
       + native
    
     
    3030    return gc;
    3131};
    3232
     33static HostLineEdit *LocalSecurityPin()
     34{
     35    HostLineEdit *gc = new HostLineEdit("SecurityPin");
     36    gc->setLabel(QObject::tr("Security Pin (Required)"));
     37    gc->setValue("");
     38    gc->setHelpText(QObject::tr("Pin code required for a frontend to connect "
     39                                "to the backend. Blank prevents all "
     40                                "connections, 0000 allows any client to "
     41                                "connect."));
     42    return gc;
     43};
     44
    3345static HostLineEdit *LocalStatusPort()
    3446{
    3547    HostLineEdit *gc = new HostLineEdit("BackendStatusPort");
     
    673685    server->addChild(LocalServerIP());
    674686    server->addChild(LocalServerPort());
    675687    server->addChild(LocalStatusPort());
     688    server->addChild(LocalSecurityPin());
    676689    server->addChild(MasterServerIP());
    677690    server->addChild(MasterServerPort());
    678691    addChild(server);
  • programs/mythbackend/mythxml.cpp

     
    14481448    QString sPin         = pRequest->m_mapParams[ "Pin" ];
    14491449    QString sSecurityPin = gContext->GetSetting( "SecurityPin", "");
    14501450
    1451     if (( sSecurityPin.length() != 0 ) && ( sPin != sSecurityPin ))
     1451    if ((sSecurityPin != "0000" ) && (( sSecurityPin.length() == 0 )
     1452        || ( sPin != sSecurityPin )))
    14521453    {
    14531454        UPnp::FormatErrorResponse( pRequest, UPnPResult_ActionNotAuthorized );
    14541455        return;
  • programs/mythbackend/main.cpp

     
    403403            extern const char *myth_source_path;
    404404            cout << "Library API version     : " << MYTH_BINARY_VERSION << endl;
    405405            cout << "Source code version     : " << myth_source_version << endl;
    406             cout << "SVN branch              : " << myth_source_path << endl;
     406            cout << "Source Branch           : " << myth_source_path << endl;
    407407            cout << "Network Protocol Version: " << MYTH_PROTO_VERSION << endl;
    408408#ifdef MYTH_BUILD_CONFIG
    409409            cout << "Options compiled in:" <<endl;