1 /***************************************************************************
2  *
3  *
4  * Project:  OpenCPN
5  * Purpose:  PlugIn Manager Object
6  * Author:   David Register
7  *
8  ***************************************************************************
9  *   Copyright (C) 2010 by David S. Register                               *
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  *   This program is distributed in the hope that it will be useful,       *
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
19  *   GNU General Public License for more details.                          *
20  *                                                                         *
21  *   You should have received a copy of the GNU General Public License     *
22  *   along with this program; if not, write to the                         *
23  *   Free Software Foundation, Inc.,                                       *
24  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
25  **************************************************************************/
26 
27 #ifndef _PLUGINMGR_H_
28 #define _PLUGINMGR_H_
29 
30 #include <wx/wx.h>
31 #include <wx/dynarray.h>
32 #include <wx/dynlib.h>
33 
34 #ifdef ocpnUSE_GL
35 #include <wx/glcanvas.h>
36 #endif
37 
38 #include "config.h"
39 
40 #include "ocpn_plugin.h"
41 #include "chart1.h"                 // for MyFrame
42 //#include "chcanv.h"                 // for ViewPort
43 #include "OCPN_Sound.h"
44 #include "chartimg.h"
45 #include "catalog_parser.h"
46 
47 #include "s57chart.h"               // for Object list
48 #include "semantic_vers.h"
49 
50 //For widgets...
51 #include "wx/hyperlink.h"
52 #include <wx/choice.h>
53 #include <wx/tglbtn.h>
54 #include <wx/bmpcbox.h>
55 
56 #ifndef __OCPN__ANDROID__
57 #ifdef OCPN_USE_CURL
58 #include "wx/curl/http.h"
59 #include "wx/curl/dialog.h"
60 #endif
61 #endif
62 
63 //    Include wxJSON headers
64 //    We undefine MIN/MAX so avoid warning of redefinition coming from
65 //    json_defs.h
66 //    Definitions checked manually, and are identical
67 #ifdef MIN
68 #undef MIN
69 #endif
70 
71 #ifdef MAX
72 #undef MAX
73 #endif
74 
75 #include <wx/json_defs.h>
76 #include <wx/jsonwriter.h>
77 
78 //    Assorted static helper routines
79 
80 PlugIn_AIS_Target *Create_PI_AIS_Target(AIS_Target_Data *ptarget);
81 
82 class PluginListPanel;
83 class PluginPanel;
84 class pluginUtilHandler;
85 
86 typedef struct {
87     wxString name;      // name of the plugin
88     int version_major;  // major version
89     int version_minor;  // minor version
90     bool hard;          // hard blacklist - if true, don't load it at all, if false, load it and just warn the user
91     bool all_lower;     // if true, blacklist also all the lower versions of the plugin
92 } BlackListedPlugin;
93 
94 const BlackListedPlugin PluginBlacklist[] = {
95     { _T("aisradar_pi"), 0, 95, true, true },
96     { _T("radar_pi"), 0, 95, true, true },             // GCC alias for aisradar_pi
97     { _T("watchdog_pi"), 1, 00, true, true },
98     { _T("squiddio_pi"), 0, 2, true, true },
99     { _T("objsearch_pi"), 0, 3, true, true },
100 #ifdef __WXOSX__
101     { _T("s63_pi"), 0, 6, true, true },
102 #endif
103 };
104 
105 //----------------------------------------------------------------------------
106 // PlugIn Messaging scheme Event
107 //----------------------------------------------------------------------------
108 
109 class OCPN_MsgEvent: public wxEvent
110 {
111 public:
112     OCPN_MsgEvent( wxEventType commandType = wxEVT_NULL, int id = 0 );
113 
OCPN_MsgEvent(const OCPN_MsgEvent & event)114     OCPN_MsgEvent(const OCPN_MsgEvent & event)
115     : wxEvent(event),
116     m_MessageID(event.m_MessageID),
117     m_MessageText(event.m_MessageText)
118     { }
119 
120     ~OCPN_MsgEvent( );
121 
122     // accessors
GetID()123     wxString GetID() { return m_MessageID; }
GetJSONText()124     wxString GetJSONText() { return m_MessageText; }
125 
SetID(const wxString & string)126     void SetID(const wxString &string) { m_MessageID = string; }
SetJSONText(const wxString & string)127     void SetJSONText(const wxString &string) { m_MessageText = string; }
128 
129 
130     // required for sending with wxPostEvent()
131     wxEvent *Clone() const;
132 
133 private:
134     wxString    m_MessageID;
135     wxString    m_MessageText;
136 
137 
138 };
139 
140 extern  const wxEventType wxEVT_OCPN_MSG;
141 
142 enum class PluginStatus {
143     System,    // One of the four system plugins, unmanaged.
144     Managed,   // Managed by installer.
145     Unmanaged, // Unmanaged, probably a package.
146     Ghost,      // Managed, shadowing another (packaged?) plugin.
147     Unknown,
148     LegacyUpdateAvailable,
149     ManagedInstallAvailable,
150     ManagedInstalledUpdateAvailable,
151     ManagedInstalledCurrentVersion,
152     ManagedInstalledDowngradeAvailable,
153     PendingListRemoval
154 };
155 
156 enum ActionVerb {
157     NOP = 0,
158     UPGRADE_TO_MANAGED_VERSION,
159     UPGRADE_INSTALLED_MANAGED_VERSION,
160     REINSTALL_MANAGED_VERSION,
161     DOWNGRADE_INSTALLED_MANAGED_VERSION,
162     UNINSTALL_MANAGED_VERSION,
163     INSTALL_MANAGED_VERSION
164 };
165 
166 // Fwd definitions
167 class StatusIconPanel;
168 
169 //-----------------------------------------------------------------------------------------------------
170 //
171 //          The PlugIn Container Specification
172 //
173 //-----------------------------------------------------------------------------------------------------
174 class PlugInContainer
175 {
176       public:
177             PlugInContainer();
178 
179             opencpn_plugin    *m_pplugin;
180             bool              m_bEnabled;
181             bool              m_bInitState;
182             bool              m_bToolboxPanel;
183             int               m_cap_flag;             // PlugIn Capabilities descriptor
184             wxString          m_plugin_file;          // The full file path
185             wxString          m_plugin_filename;      // The short file path
186             wxDateTime        m_plugin_modification;  // used to detect upgraded plugins
187             destroy_t         *m_destroy_fn;
188             wxDynamicLibrary  m_library;
189             wxString          m_common_name;            // A common name string for the plugin
190             wxString          m_short_description;
191             wxString          m_long_description;
192             int               m_api_version;
193             int               m_version_major;
194             int               m_version_minor;
195             wxBitmap         *m_bitmap;
196             /**
197              * Return version from plugin API. Older pre-117 plugins just
198              * support major and minor version, newer plugins have
199              * complete semantic version data.
200              */
201             SemanticVersion   GetVersion();
202             wxString          m_version_str;    // Complete version as of
203                                                 // semantic_vers
204             PluginStatus      m_pluginStatus;
205             std::string       m_InstalledManagedVersion;  // As detected from manifest
206             PluginMetadata    m_ManagedMetadata;
207 };
208 
209 //    Declare an array of PlugIn Containers
210 WX_DEFINE_ARRAY_PTR(PlugInContainer *, ArrayOfPlugIns);
211 
212 class PlugInMenuItemContainer
213 {
214       public:
215             wxMenuItem        *pmenu_item;
216             opencpn_plugin    *m_pplugin;
217             bool              b_viz;
218             bool              b_grey;
219             int               id;
220             wxString          m_in_menu;
221 };
222 
223 //    Define an array of PlugIn MenuItem Containers
224 WX_DEFINE_ARRAY_PTR(PlugInMenuItemContainer *, ArrayOfPlugInMenuItems);
225 
226 
227 class PlugInToolbarToolContainer
228 {
229       public:
230             PlugInToolbarToolContainer();
231             ~PlugInToolbarToolContainer();
232 
233             opencpn_plugin    *m_pplugin;
234             int               id;
235             wxString          label;
236             wxBitmap          *bitmap_day;
237             wxBitmap          *bitmap_dusk;
238             wxBitmap          *bitmap_night;
239             wxBitmap          *bitmap_Rollover_day;
240             wxBitmap          *bitmap_Rollover_dusk;
241             wxBitmap          *bitmap_Rollover_night;
242 
243             wxItemKind        kind;
244             wxString          shortHelp;
245             wxString          longHelp;
246             wxObject          *clientData;
247             int               position;
248             bool              b_viz;
249             bool              b_toggle;
250             int               tool_sel;
251             wxString          pluginNormalIconSVG;
252             wxString          pluginRolloverIconSVG;
253             wxString          pluginToggledIconSVG;
254 
255 };
256 
257 //    Define an array of PlugIn ToolbarTool Containers
258 WX_DEFINE_ARRAY_PTR(PlugInToolbarToolContainer *, ArrayOfPlugInToolbarTools);
259 
260 
261 
262 //-----------------------------------------------------------------------------------------------------
263 //
264 //          The PlugIn Manager Specification
265 //
266 //-----------------------------------------------------------------------------------------------------
267 
268 class PlugInManager: public wxEvtHandler
269 {
270 
271 public:
272       PlugInManager(MyFrame *parent);
273       virtual ~PlugInManager();
274 
275       bool LoadAllPlugIns(bool enabled_plugins, bool b_enable_blackdialog = true);
276 
277       /** Unload, delete and remove item ix in GetPlugInArray(). */
278       bool UnLoadPlugIn(size_t ix);
279 
280       bool UnLoadAllPlugIns();
281       bool DeactivateAllPlugIns();
282       bool DeactivatePlugIn(PlugInContainer *pic);
283       bool UpdatePlugIns();
284 
285       bool UpdateConfig();
286 
287       PlugInContainer *LoadPlugIn(wxString plugin_file);
GetPlugInArray()288       ArrayOfPlugIns *GetPlugInArray(){ return &plugin_array; }
289 
290       bool RenderAllCanvasOverlayPlugIns( ocpnDC &dc, const ViewPort &vp, int canvasIndex);
291       bool RenderAllGLCanvasOverlayPlugIns( wxGLContext *pcontext, const ViewPort &vp, int canvasIndex);
292       void SendCursorLatLonToAllPlugIns( double lat, double lon);
293       void SendViewPortToRequestingPlugIns( ViewPort &vp );
294       void PrepareAllPluginContextMenus();
295 
296       void NotifySetupOptions();
297       void ClosePlugInPanel(PlugInContainer* pic, int ix);
298       void CloseAllPlugInPanels( int );
299 
GetPluginToolbarToolArray()300       ArrayOfPlugInToolbarTools &GetPluginToolbarToolArray(){ return m_PlugInToolbarTools; }
301       int AddToolbarTool(wxString label, wxBitmap *bitmap, wxBitmap *bmpRollover,
302                          wxItemKind kind, wxString shortHelp, wxString longHelp,
303                          wxObject *clientData, int position,
304                          int tool_sel, opencpn_plugin *pplugin );
305 
306       void RemoveToolbarTool(int tool_id);
307       void SetToolbarToolViz(int tool_id, bool viz);
308       void SetToolbarItemState(int tool_id, bool toggle);
309       void SetToolbarItemBitmaps(int item, wxBitmap *bitmap, wxBitmap *bmpDisabled);
310 
311       int AddToolbarTool(wxString label, wxString SVGfile, wxString SVGRolloverfile, wxString SVGToggledfile,
312                          wxItemKind kind, wxString shortHelp, wxString longHelp,
313                          wxObject *clientData, int position,
314                          int tool_sel, opencpn_plugin *pplugin );
315 
316       void SetToolbarItemBitmaps(int item, wxString SVGfile,
317                                  wxString SVGfileRollover,
318                                  wxString SVGfileToggled);
319 
320       opencpn_plugin *FindToolOwner(const int id);
321       wxString GetToolOwnerCommonName(const int id);
322       void ShowDeferredBlacklistMessages();
323 
GetPluginContextMenuItemArray()324       ArrayOfPlugInMenuItems &GetPluginContextMenuItemArray(){ return m_PlugInMenuItems; }
325       int AddCanvasContextMenuItem(wxMenuItem *pitem, opencpn_plugin *pplugin, const char *name = "" );
326       void RemoveCanvasContextMenuItem(int item, const char *name = "" );
327       void SetCanvasContextMenuItemViz(int item, bool viz, const char *name = "" );
328       void SetCanvasContextMenuItemGrey(int item, bool grey, const char *name = "" );
329 
330       void SendNMEASentenceToAllPlugIns(const wxString &sentence);
331       void SendPositionFixToAllPlugIns(GenericPosDatEx *ppos);
332       void SendActiveLegInfoToAllPlugIns(ActiveLegDat *infos);
333       void SendAISSentenceToAllPlugIns(const wxString &sentence);
334       void SendJSONMessageToAllPlugins(const wxString &message_id, wxJSONValue v);
335       void SendMessageToAllPlugins(const wxString &message_id, const wxString &message_body);
336       int GetJSONMessageTargetCount();
337 
338       void SendResizeEventToAllPlugIns(int x, int y);
339       void SetColorSchemeForAllPlugIns(ColorScheme cs);
340       void NotifyAuiPlugIns(void);
341       bool CallLateInit(void);
342 
343       bool IsPlugInAvailable(wxString commonName);
344       bool IsAnyPlugInChartEnabled();
345 
346       void SendVectorChartObjectInfo(const wxString &chart, const wxString &feature, const wxString &objname, double &lat, double &lon, double &scale, int &nativescale);
347 
348       bool SendMouseEventToPlugins( wxMouseEvent &event);
349       bool SendKeyEventToPlugins( wxKeyEvent &event);
350 
351       void SendBaseConfigToAllPlugIns();
352       void SendS52ConfigToAllPlugIns( bool bReconfig = false );
353       void SendSKConfigToAllPlugIns();
354 
355       void UpdateManagedPlugins();
356 
357       wxArrayString GetPlugInChartClassNameArray(void);
358 
359       ListOfPI_S57Obj *GetPlugInObjRuleListAtLatLon( ChartPlugInWrapper *target, float zlat, float zlon,
360                                                        float SelectRadius, const ViewPort& vp );
361       wxString CreateObjDescriptions( ChartPlugInWrapper *target, ListOfPI_S57Obj *rule_list );
362 
363       wxString GetLastError();
GetParentFrame()364       MyFrame *GetParentFrame(){ return pParent; }
365 
366       void DimeWindow(wxWindow *win);
GetUtilHandler()367       pluginUtilHandler *GetUtilHandler(){ return m_utilHandler; }
SetListPanelPtr(PluginListPanel * ptr)368       void SetListPanelPtr( PluginListPanel *ptr ) { m_listPanel = ptr; }
369       bool CheckPluginCompatibility(wxString plugin_file);
370 
371 private:
372       bool CheckBlacklistedPlugin(opencpn_plugin* plugin);
373       wxBitmap *BuildDimmedToolBitmap(wxBitmap *pbmp_normal, unsigned char dim_ratio);
374       bool UpDateChartDataTypes(void);
375       bool LoadPlugInDirectory(const wxString &plugin_dir, bool enabled_plugins, bool b_enable_blackdialog);
376       void ProcessLateInit(PlugInContainer *pic);
377 
378       MyFrame                 *pParent;
379 
380       ArrayOfPlugIns    plugin_array;
381       wxString          m_last_error_string;
382 
383       ArrayOfPlugInMenuItems        m_PlugInMenuItems;
384       ArrayOfPlugInToolbarTools     m_PlugInToolbarTools;
385 
386       wxString          m_plugin_location;
387 
388       int               m_plugin_tool_id_next;
389       int               m_plugin_menu_item_id_next;
390       wxBitmap          m_cached_overlay_bm;
391 
392       bool              m_benable_blackdialog;
393       bool              m_benable_blackdialog_done;
394       wxArrayString     m_deferred_blacklist_messages;
395 
396       wxArrayString     m_plugin_order;
397       void SetPluginOrder( wxString serialized_names );
398       wxString GetPluginOrder();
399 
400       pluginUtilHandler *m_utilHandler;
401       PluginListPanel   *m_listPanel;
402 
403 
404 #ifndef __OCPN__ANDROID__
405 #ifdef OCPN_USE_CURL
406 
407 public:
408       wxCurlDownloadThread *m_pCurlThread;
409       // The libcurl handle being re used for the transfer.
410       std::shared_ptr<wxCurlBase> m_pCurl;
411 
412       // returns true if the error can be ignored
413       bool            HandleCurlThreadError(wxCurlThreadError err, wxCurlBaseThread *p,
414                                const wxString &url = wxEmptyString);
415       void            OnEndPerformCurlDownload(wxCurlEndPerformEvent &ev);
416       void            OnCurlDownload(wxCurlDownloadEvent &ev);
417 
418       wxEvtHandler   *m_download_evHandler;
419       long           *m_downloadHandle;
420       bool m_last_online;
421       long m_last_online_chk;
422 #endif
423 #endif
424 
425 DECLARE_EVENT_TABLE()
426 };
427 
428 WX_DEFINE_ARRAY_PTR(PluginPanel *, ArrayOfPluginPanel);
429 
430 class PluginDownloadDialog;
431 
432 /*
433  * Panel with a single + sign which opens the "Add/download plugins" dialog.
434  */
435 class AddPluginPanel: public wxPanel
436 {
437     public:
438         AddPluginPanel(wxWindow* parent);
439         void OnClick(wxMouseEvent& event);
440         ~AddPluginPanel();
441 
442     protected:
443         wxBitmap m_bitmap;
444         wxStaticBitmap* m_staticBitmap;
445         wxWindow* m_parent;
446 };
447 
448 
449 /*
450  * Panel with buttons to control plugin catalog management.
451  */
452 class CatalogMgrPanel: public wxPanel
453 {
454     public:
455         CatalogMgrPanel(wxWindow* parent);
456         ~CatalogMgrPanel();
457         void OnUpdateButton(wxCommandEvent &event);
458         void OnChannelSelected(wxCommandEvent &event);
SetListPanelPtr(PluginListPanel * listPanel)459         void SetListPanelPtr(PluginListPanel *listPanel){ m_PluginListPanel = listPanel; }
460         void OnTarballButton(wxCommandEvent &event);
461     protected:
462         wxString GetCatalogText(bool);
463         unsigned int GetChannelIndex(const wxArrayString* channels);
464         void SetUpdateButtonLabel();
465 
466         wxButton *m_updateButton, *m_advancedButton, *m_tarballButton;
467         wxStaticText *m_catalogText, *m_customText;
468         wxChoice *m_choiceChannel;
469         wxTextCtrl *m_tcCustomURL;
470         wxWindow* m_parent;
471         PluginListPanel *m_PluginListPanel;
472 };
473 
474 
475 #define ID_CMD_BUTTON_PERFORM_ACTION 27663
476 
477 class PluginListPanel: public wxScrolledWindow
478 {
479       DECLARE_EVENT_TABLE()
480 
481 public:
482       PluginListPanel( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, ArrayOfPlugIns *pPluginArray );
483       ~PluginListPanel();
484 
485       void SelectPlugin( PluginPanel *pi );
486       void MoveUp( PluginPanel *pi );
487       void MoveDown( PluginPanel *pi );
488       void UpdateSelections();
489       void UpdatePluginsOrder();
490 
491       /** Complete reload from plugins array. */
492       void ReloadPluginPanels(ArrayOfPlugIns* plugins);
493       void SelectByName(wxString &name);
494 
495       wxBoxSizer         *m_pitemBoxSizer01;
496 private:
497       void AddPlugin(PlugInContainer* pic);
498       int ComputePluginSpace(ArrayOfPluginPanel plugins, wxBoxSizer* sizer);
499       //void Clear();
500 
501       wxPanel            *m_panel;
502       ArrayOfPlugIns     *m_pPluginArray;
503       ArrayOfPluginPanel  m_PluginItems;
504       PluginPanel        *m_PluginSelected;
505       wxString            m_selectedName;
506       int                 m_pluginSpacer;
507 };
508 
509 /** Invokes client browser on plugin info_url when clicked. */
510 class WebsiteButton: public wxPanel
511 {
512     public:
513         WebsiteButton(wxWindow* parent, const char* url);
~WebsiteButton()514         ~WebsiteButton(){};
SetURL(std::string url)515         void SetURL( std::string url){ m_url = url; }
516     protected:
517         std::string m_url;
518 };
519 
520 class PluginPanel: public wxPanel
521 {
522       DECLARE_EVENT_TABLE()
523 
524 public:
525       PluginPanel( wxPanel *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, PlugInContainer *p_plugin );
526       ~PluginPanel();
527 
528       void OnPluginSelected( wxMouseEvent &event );
529       void OnPluginSelectedUp( wxMouseEvent &event );
530       void DoPluginSelect();
531 
532       void SetSelected( bool selected );
533       void OnPluginPreferences( wxCommandEvent& event );
534       void OnPluginEnableToggle( wxCommandEvent& event );
535       void OnPluginAction( wxCommandEvent& event );
536       void OnPluginUninstall( wxCommandEvent& event );
537       void OnPluginUp( wxCommandEvent& event );
538       void OnPluginDown( wxCommandEvent& event );
539       void SetEnabled( bool enabled );
GetSelected()540       bool GetSelected(){ return m_bSelected; }
GetPluginPtr()541       PlugInContainer* GetPluginPtr() { return m_pPlugin; };
542       void SetActionLabel( wxString &label);
GetAction()543       ActionVerb GetAction() { return m_action; }
GetPlugin()544       PlugInContainer* GetPlugin() { return m_pPlugin; }
545       void OnPaint(wxPaintEvent &event);
546 
547 private:
548       PluginListPanel *m_PluginListPanel;
549       bool             m_bSelected;
550       PlugInContainer *m_pPlugin;
551       StatusIconPanel *m_status_icon;
552       wxStaticText    *m_pName;
553       wxStaticText    *m_pVersion;
554       wxStaticText    *m_pDescription;
555       wxBoxSizer      *m_pButtons;
556       wxStaticBitmap  *m_itemStaticBitmap;
557       wxButton        *m_pButtonPreferences;
558       wxButton        *m_pButtonAction, *m_pButtonUninstall;
559 
560       wxCheckBox      *m_cbEnable;
561       WebsiteButton   *m_info_btn;
562       ActionVerb      m_action;
563       int              m_penWidthUnselected, m_penWidthSelected;
564 
565 };
566 
567 
568 //  API 1.11 adds access to S52 Presentation library
569 //  These are some wrapper conversion utilities
570 
571 class S52PLIB_Context
572 {
573 public:
S52PLIB_Context()574     S52PLIB_Context(){
575         bBBObj_valid = false;
576         bCS_Added = false;
577         bFText_Added = false;
578         CSrules = NULL;
579         FText = NULL;
580         ChildRazRules = NULL;
581         MPSRulesList = NULL;
582         LUP = NULL;
583         };
584 
~S52PLIB_Context()585     ~S52PLIB_Context(){};
586 
587     wxBoundingBox           BBObj;                  // lat/lon BBox of the rendered object
588     bool                    bBBObj_valid;           // set after the BBObj has been calculated once.
589 
590     Rules                   *CSrules;               // per object conditional symbology
591     int                     bCS_Added;
592 
593     S52_TextC                *FText;
594     int                     bFText_Added;
595     wxRect                  rText;
596 
597     LUPrec                  *LUP;
598     ObjRazRules             *ChildRazRules;
599     mps_container           *MPSRulesList;
600 };
601 
602 
603 void CreateCompatibleS57Object( PI_S57Obj *pObj, S57Obj *cobj, chart_context *pctx );
604 void UpdatePIObjectPlibContext( PI_S57Obj *pObj, S57Obj *cobj );
605 
606 #endif            // _PLUGINMGR_H_
607 
608