1 /**
2  * @file
3  * Simple Pager Dialog
4  *
5  * @authors
6  * Copyright (C) 1996-2002,2007,2010,2012-2013 Michael R. Elkins <me@mutt.org>
7  * Copyright (C) 2020 R Primus <rprimus@gmail.com>
8  *
9  * @copyright
10  * This program is free software: you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free Software
12  * Foundation, either version 2 of the License, or (at your option) any later
13  * version.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 /**
25  * @page pager_dopager Simple Pager Dialog
26  *
27  * The Simple Pager Dialog displays text to the user that can be paged.
28  *
29  * ## Windows
30  *
31  * | Name                | Type             | Constructor     |
32  * | :------------------ | :--------------- | :-------------- |
33  * | Simple Pager Dialog | #WT_DLG_DO_PAGER | mutt_do_pager() |
34  *
35  * **Parent**
36  * - @ref gui_dialog
37  *
38  * **Children**
39  * - @ref pager_ppanel
40  *
41  * ## Data
42  *
43  * The Simple Pager Dialog has no data.
44  *
45  * ## Events
46  *
47  * Once constructed, it is controlled by the following events:
48  *
49  * | Event Type  | Handler                   |
50  * | :---------- | :------------------------ |
51  * | #NT_CONFIG  | dopager_config_observer() |
52  * | #NT_WINDOW  | dopager_window_observer() |
53  *
54  * The Simple Pager Dialog does not implement MuttWindow::recalc() or
55  * MuttWindow::repaint().
56  */
57 
58 #include "config.h"
59 #include <stddef.h>
60 #include <assert.h>
61 #include <stdbool.h>
62 #include "mutt/lib.h"
63 #include "config/lib.h"
64 #include "core/lib.h"
65 #include "gui/lib.h"
66 #include "lib.h"
67 #include "index/lib.h"
68 #include "protos.h"
69 
70 struct Email;
71 
72 /**
73  * dopager_config_observer - Notification that a Config Variable has changed - Implements ::observer_t - @ingroup observer_api
74  */
dopager_config_observer(struct NotifyCallback * nc)75 static int dopager_config_observer(struct NotifyCallback *nc)
76 {
77   if ((nc->event_type != NT_CONFIG) || !nc->global_data || !nc->event_data)
78     return -1;
79 
80   struct EventConfig *ev_c = nc->event_data;
81   if (!mutt_str_equal(ev_c->name, "status_on_top"))
82     return 0;
83 
84   struct MuttWindow *dlg = nc->global_data;
85   window_status_on_top(dlg, NeoMutt->sub);
86   mutt_debug(LL_DEBUG5, "config done, request WA_REFLOW\n");
87   return 0;
88 }
89 
90 /**
91  * dopager_window_observer - Notification that a Window has changed - Implements ::observer_t - @ingroup observer_api
92  */
dopager_window_observer(struct NotifyCallback * nc)93 static int dopager_window_observer(struct NotifyCallback *nc)
94 {
95   if ((nc->event_type != NT_WINDOW) || !nc->global_data || !nc->event_data)
96     return -1;
97 
98   if (nc->event_subtype != NT_WINDOW_DELETE)
99     return 0;
100 
101   struct MuttWindow *dlg = nc->global_data;
102   struct EventWindow *ev_w = nc->event_data;
103   if (ev_w->win != dlg)
104     return 0;
105 
106   notify_observer_remove(NeoMutt->notify, dopager_config_observer, dlg);
107   notify_observer_remove(dlg->notify, dopager_window_observer, dlg);
108   mutt_debug(LL_DEBUG5, "window delete done\n");
109 
110   return 0;
111 }
112 
113 /**
114  * mutt_do_pager - Display some page-able text to the user (help or attachment)
115  * @param pview PagerView to construct Pager object
116  * @param e     Email to use
117  * @retval  0 Success
118  * @retval -1 Error
119  */
mutt_do_pager(struct PagerView * pview,struct Email * e)120 int mutt_do_pager(struct PagerView *pview, struct Email *e)
121 {
122   assert(pview);
123   assert(pview->pdata);
124   assert(pview->pdata->fname);
125   assert((pview->mode == PAGER_MODE_ATTACH) ||
126          (pview->mode == PAGER_MODE_HELP) || (pview->mode == PAGER_MODE_OTHER));
127 
128   struct MuttWindow *dlg =
129       mutt_window_new(WT_DLG_DO_PAGER, MUTT_WIN_ORIENT_VERTICAL, MUTT_WIN_SIZE_MAXIMISE,
130                       MUTT_WIN_SIZE_UNLIMITED, MUTT_WIN_SIZE_UNLIMITED);
131 
132   struct IndexSharedData *shared = index_shared_data_new();
133   shared->email = e;
134 
135   notify_set_parent(shared->notify, dlg->notify);
136 
137   dlg->wdata = shared;
138   dlg->wdata_free = index_shared_data_free;
139 
140   const bool c_status_on_top = cs_subset_bool(NeoMutt->sub, "status_on_top");
141   struct MuttWindow *panel_pager = ppanel_new(c_status_on_top, shared);
142   dlg->focus = panel_pager;
143   mutt_window_add_child(dlg, panel_pager);
144 
145   notify_observer_add(NeoMutt->notify, NT_CONFIG, dopager_config_observer, dlg);
146   notify_observer_add(dlg->notify, NT_WINDOW, dopager_window_observer, dlg);
147   dialog_push(dlg);
148 
149   pview->win_index = NULL;
150   pview->win_pbar = window_find_child(panel_pager, WT_STATUS_BAR);
151   pview->win_pager = window_find_child(panel_pager, WT_CUSTOM);
152 
153   int rc;
154 
155   const char *const c_pager = cs_subset_string(NeoMutt->sub, "pager");
156   if (!c_pager || mutt_str_equal(c_pager, "builtin"))
157   {
158     rc = mutt_pager(pview);
159   }
160   else
161   {
162     struct Buffer *cmd = mutt_buffer_pool_get();
163 
164     mutt_endwin();
165     mutt_buffer_file_expand_fmt_quote(cmd, c_pager, pview->pdata->fname);
166     if (mutt_system(mutt_buffer_string(cmd)) == -1)
167     {
168       mutt_error(_("Error running \"%s\""), mutt_buffer_string(cmd));
169       rc = -1;
170     }
171     else
172       rc = 0;
173     mutt_file_unlink(pview->pdata->fname);
174     mutt_buffer_pool_release(&cmd);
175   }
176 
177   dialog_pop();
178   mutt_window_free(&dlg);
179   return rc;
180 }
181