1/////////////////////////////////////////////////////////////////////////////
2// Name:        remhelp.cpp
3// Purpose:     Remote help controller class
4// Author:      Eric Dowty
5// Modified by:
6// Created:     2002-11-18
7// RCS-ID:      $Id: remhelp.cpp 35650 2005-09-23 12:56:45Z MR $
8// Copyright:   (c) Julian Smart
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16    #pragma hdrstop
17#endif
18
19#ifndef WX_PRECOMP
20    #include "wx/wx.h"
21#endif
22
23#include <math.h>
24
25#include "wx/process.h"
26#include "wx/confbase.h"
27
28// Settings common to both executables: determines whether
29// we're using TCP/IP or real DDE.
30
31//#include "ddesetup.h"
32//#define wxUSE_DDE_FOR_IPC 0
33
34#if defined(__WXGTK__) || defined(__WXMOTIF__)
35#include "mondrian.xpm"
36#endif
37
38#include "remhelp.h"
39#include "client.h"
40
41#if !defined(USE_REMOTE)
42#include <wx/html/helpctrl.h>
43#endif
44
45//////////////////
46//////////////////
47// helper classes
48
49rhhcClient::rhhcClient( bool *isconn_a )
50{
51    isconn_2 = isconn_a;
52}
53
54wxConnectionBase *rhhcClient::OnMakeConnection()
55{
56    return new rhhcConnection( isconn_2 );
57}
58
59rhhcConnection::rhhcConnection( bool *isconn_a )
60: wxConnection()
61{
62    isconn_3 = isconn_a;
63    *isconn_3 = true;
64}
65
66rhhcConnection::~rhhcConnection()
67{
68    *isconn_3 = false;
69}
70
71bool rhhcConnection::OnAdvise(const wxString& topic, const wxString& item, char *data, int size, wxIPCFormat format)
72{
73    return true;
74}
75
76bool rhhcConnection::OnDisconnect()
77{
78    *isconn_3 = false;
79
80    return wxConnection::OnDisconnect();
81}
82
83//////////////////////////////////////////
84/////////////////////////////////////////
85
86// wxRemoteHtmlHelpController class
87
88IMPLEMENT_CLASS(wxRemoteHtmlHelpController, wxHelpControllerBase)
89
90wxRemoteHtmlHelpController::wxRemoteHtmlHelpController(int style )
91{
92    m_style = style;
93    m_connection = NULL;
94    m_client  = NULL;
95    m_pid = 0;
96    isconn_1 = false;
97    m_process = NULL;
98
99    // defaults
100    //
101    // server app is assumed to be local
102    //
103    // for MSW (DDE classes), a_service is 'service name', apparently an arbitrary string
104    // for Unix, should be a valid file name (for a nonexistent file)
105    // for nonMSW, nonUnix, must be port number, for example "4242" (TCP/IP based classes)
106    // should be unique to the client app
107
108    wxString thename = wxGetApp().GetAppName();
109#if defined(__WXMSW__)
110    m_appname = wxT("helpview.exe");
111    m_service = thename + wxString(wxT("_helpservice"));
112#elif defined(__UNIX__)
113    m_appname = wxT("./helpview");
114    m_service = wxT("/tmp/") + thename + wxString(wxT("_helpservice"));
115#else
116    m_appname = wxT("./helpview");
117    m_service = wxT("4242");
118#endif
119
120    m_book = thename + wxT(".hhp");  // or .htb or .zip
121    m_windowname = thename + wxT(" Help: %s");
122    //underscores for spaces
123    m_windowname.Replace( wxT(" "), wxT("_") );
124}
125
126void wxRemoteHtmlHelpController::SetService(wxString& a_service)
127{
128    m_service = a_service;
129}
130void wxRemoteHtmlHelpController::SetServer(wxString& a_appname)
131{
132    m_appname = a_appname;
133}
134
135void wxRemoteHtmlHelpController::OnQuit()
136{
137    //kill the Server here?
138    //this function is not called ?
139}
140
141wxRemoteHtmlHelpController::~wxRemoteHtmlHelpController()
142{
143    if ( isconn_1 )
144    {
145        // if (!m_connection->Poke( wxT("--YouAreDead"), wxT("") ) )
146        // wxLogError(wxT("wxRemoteHtmlHelpController - YouAreDead Failed"));
147
148        // Kill the server.  This could be an option.
149        Quit();
150
151        m_connection->Disconnect();
152        delete m_connection;
153
154        delete m_process;
155        m_process = NULL;
156    }
157    if( m_client )
158        delete m_client; //should be automatic?
159
160}
161
162bool wxRemoteHtmlHelpController::DoConnection()
163{
164    wxString cmd, blank;
165    int nsleep;
166
167    blank = wxT("  ");
168
169    // ignored under DDE, host name in TCP/IP based classes
170    wxString hostName = wxT("localhost");
171
172    // Create a new client
173    if( !m_client ) m_client = new rhhcClient(&isconn_1);
174
175    nsleep = 0;
176
177    // suppress the log messages from MakeConnection()
178    {
179        wxLogNull nolog;
180
181        //first try to connect assuming server is running
182        if( !isconn_1 )
183            m_connection = (rhhcConnection *)m_client->MakeConnection(hostName, m_service, wxT("HELP") );
184
185        //if not, start server
186        if( !isconn_1 ) {
187
188            wxString stylestr;
189            stylestr.Printf( wxT("--Style%d"), m_style );
190
191            cmd = m_appname + blank + m_service + blank + m_windowname + blank + m_book + blank + stylestr;
192
193            m_process = new wxProcess(NULL);
194            m_pid = wxExecute( cmd, false, m_process );
195            // leaks - wxExecute itself (if not deleted) and in wxExecute at
196            // wxExecuteData *data = new wxExecuteData;
197            if( m_pid <= 0 ) {
198                wxLogError( wxT("wxRemoteHtmlHelpController - Failed to start Help server") );
199                return false;
200            }
201        }
202
203        while ( !isconn_1 )
204        {
205            //try every second for a while, then leave it to user
206            wxSleep(1);
207            if( nsleep > 4 ) {
208                if ( wxMessageBox( wxT("Failed to make connection to Help server.\nRetry?") ,
209                                   wxT("wxRemoteHtmlHelpController Error"),
210                                   wxICON_ERROR | wxYES_NO | wxCANCEL ) != wxYES )
211                {
212                    // no server
213                    return false;
214                }
215            }
216            nsleep++;
217
218            m_connection = (rhhcConnection *)m_client->MakeConnection(hostName, m_service, wxT("HELP") );
219        }
220    }
221
222    if (!m_connection->StartAdvise(wxT("Item"))) {
223        wxLogError(wxT("wxRemoteHtmlHelpController - StartAdvise failed") );
224        return false;
225    }
226
227    return true;
228}
229
230bool wxRemoteHtmlHelpController::LoadFile(const wxString& WXUNUSED(file))
231{
232    return true;
233}
234bool wxRemoteHtmlHelpController::DisplaySection(int sectionNo)
235{
236    Display(sectionNo);
237    return true;
238}
239bool wxRemoteHtmlHelpController::DisplayBlock(long blockNo)
240{
241    return DisplaySection((int)blockNo);
242}
243
244bool wxRemoteHtmlHelpController::Quit()
245{
246    //this code from exec sample - branches left in for testing
247    // sig = 3, 6, 9 or 12 all kill server with no apparent problem
248    // but give error message on MSW - timout?
249    int sig = 15;   //3 = quit; 6 = abort; 9 = kill;  15 = terminate
250
251/*
252                    switch ( sig )
253                    {
254                    default:
255                    wxFAIL_MSG( _T("unexpected return value") );
256                    // fall through
257
258                      case -1:
259                      // cancelled
260                      return false;
261
262                        case wxSIGNONE:
263                        case wxSIGHUP:
264                        case wxSIGINT:
265                        case wxSIGQUIT:
266                        case wxSIGILL:
267                        case wxSIGTRAP:
268                        case wxSIGABRT:
269                        case wxSIGEMT:
270                        case wxSIGFPE:
271                        case wxSIGKILL:
272                        case wxSIGBUS:
273                        case wxSIGSEGV:
274                        case wxSIGSYS:
275                        case wxSIGPIPE:
276                        case wxSIGALRM:
277                        case wxSIGTERM:
278                        break;
279                        }
280*/
281
282    if ( sig == 0 )
283    {
284        if ( wxProcess::Exists(m_pid) )
285            wxLogStatus(_T("Process %ld is running."), m_pid);
286        else
287            wxLogStatus(_T("No process with pid = %ld."), m_pid);
288    }
289    else // not SIGNONE
290    {
291        wxKillError rc = wxProcess::Kill(m_pid, (wxSignal)sig);
292        if ( rc == wxKILL_OK )
293        {
294            wxLogStatus(_T("Process %ld killed with signal %d."), m_pid, sig);
295        }
296        else
297        {
298            static const wxChar *errorText[] =
299            {
300                _T(""), // no error
301                    _T("signal not supported"),
302                    _T("permission denied"),
303                    _T("no such process"),
304                    _T("unspecified error"),
305            };
306
307            // sig = 3, 6, 9 or 12 all kill server with no apparent problem
308            // but give error message on MSW - timout?
309            //
310            //wxLogError(_T("Failed to kill process %ld with signal %d: %s"),
311            //            m_pid, sig, errorText[rc]);
312        }
313    }
314
315
316    return true;
317}
318
319void wxRemoteHtmlHelpController::Display(const wxString& helpfile)
320{
321    if( !isconn_1 ) {
322        if( !DoConnection() ) return;
323    }
324
325    if (!m_connection->Execute( helpfile, -1 ) )
326        wxLogError(wxT("wxRemoteHtmlHelpController - Display Failed"));
327
328}
329
330void wxRemoteHtmlHelpController::Display(const int id)
331{
332    if( !isconn_1 ) {
333        if( !DoConnection() ) return;
334    }
335
336    wxString intstring;
337    intstring.Printf( "--intstring%d", id );
338
339    if (!m_connection->Execute( intstring, -1 ) )
340        wxLogError(wxT("wxRemoteHtmlHelpController - Display Failed"));
341
342}
343
344bool wxRemoteHtmlHelpController::AddBook(const wxString& book, bool show_wait_msg)
345{
346    //ignore show_wait_msg - there shouldn't be a delay in this step
347    //show_wait_msg = true could be transmitted with ++AddBook
348    m_book = book;
349
350    if( isconn_1 ) {
351        if (!m_connection->Poke( wxT("--AddBook"), (char*)book.c_str() ) )
352            wxLogError(wxT("wxRemoteHtmlHelpController - AddBook Failed"));
353        return false;
354    }
355
356    return true;
357}
358
359bool wxRemoteHtmlHelpController::DisplayContents()
360{
361    if( isconn_1 ) {
362        if (!m_connection->Poke( wxT("--DisplayContents"), wxT("") ) ) {
363            wxLogError(wxT("wxRemoteHtmlHelpController - DisplayContents Failed"));
364            return false;
365        }
366    }
367    return true;
368}
369void wxRemoteHtmlHelpController::DisplayIndex()
370{
371    if( isconn_1 ) {
372        if (!m_connection->Poke( wxT("--DisplayIndex"), wxT("") ) )
373            wxLogError(wxT("wxRemoteHtmlHelpController - DisplayIndex Failed"));
374    }
375}
376bool wxRemoteHtmlHelpController::KeywordSearch(const wxString& keyword)
377{
378    if( isconn_1 ) {
379        if (!m_connection->Poke( wxT("--KeywordSearch"), (char*)keyword.c_str() ) ) {
380            wxLogError(wxT("wxRemoteHtmlHelpController - KeywordSearch Failed"));
381            return false;
382        }
383    }
384    return true;
385}
386
387void wxRemoteHtmlHelpController::SetTitleFormat(const wxString& format)
388{
389    m_windowname = format;
390    m_windowname.Replace( wxT(" "), wxT("_") );
391
392    if( isconn_1 ) {
393        if (!m_connection->Poke( wxT("--SetTitleFormat"), (char*)format.c_str() ) )
394            wxLogError(wxT("wxRemoteHtmlHelpController - SetTitleFormat Failed"));
395    }
396}
397
398void wxRemoteHtmlHelpController::SetTempDir(const wxString& path)
399{
400    if( isconn_1 ) {
401        if (!m_connection->Poke( wxT("--SetTempDir"), (char*)path.c_str() ) )
402            wxLogError(wxT("wxRemoteHtmlHelpController - SetTempDir Failed"));
403    }
404}
405
406