/src/neomutt/attach/dlg_attach.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file |
3 | | * Attachment Selection Dialog |
4 | | * |
5 | | * @authors |
6 | | * Copyright (C) 1996-2000,2002,2007,2010 Michael R. Elkins <me@mutt.org> |
7 | | * Copyright (C) 1999-2006 Thomas Roessler <roessler@does-not-exist.org> |
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 attach_dlg_attach Attachment Selection Dialog |
26 | | * |
27 | | * The Attachment Selection Dialog lets the user select an email attachment. |
28 | | * |
29 | | * This is a @ref gui_simple |
30 | | * |
31 | | * ## Windows |
32 | | * |
33 | | * | Name | Type | See Also | |
34 | | * | :-------------------------- | :---------------- | :--------------- | |
35 | | * | Attachment Selection Dialog | WT_DLG_ATTACHMENT | dlg_attachment() | |
36 | | * |
37 | | * **Parent** |
38 | | * - @ref gui_dialog |
39 | | * |
40 | | * **Children** |
41 | | * - See: @ref gui_simple |
42 | | * |
43 | | * ## Data |
44 | | * - #Menu |
45 | | * - #Menu::mdata |
46 | | * - #AttachCtx |
47 | | * |
48 | | * The @ref gui_simple holds a Menu. The Attachment Selection Dialog stores |
49 | | * its data (#AttachCtx) in Menu::mdata. |
50 | | * |
51 | | * ## Events |
52 | | * |
53 | | * Once constructed, it is controlled by the following events: |
54 | | * |
55 | | * | Event Type | Handler | |
56 | | * | :---------- | :----------------------- | |
57 | | * | #NT_CONFIG | attach_config_observer() | |
58 | | * | #NT_WINDOW | attach_window_observer() | |
59 | | * |
60 | | * The Attachment Selection Dialog doesn't have any specific colours, so it |
61 | | * doesn't need to support #NT_COLOR. |
62 | | * |
63 | | * The Attachment Selection Dialog does not implement MuttWindow::recalc() or |
64 | | * MuttWindow::repaint(). |
65 | | * |
66 | | * Some other events are handled by the @ref gui_simple. |
67 | | */ |
68 | | |
69 | | #include "config.h" |
70 | | #include <stdbool.h> |
71 | | #include <stdint.h> |
72 | | #include <stdio.h> |
73 | | #include "mutt/lib.h" |
74 | | #include "config/lib.h" |
75 | | #include "email/lib.h" |
76 | | #include "core/lib.h" |
77 | | #include "gui/lib.h" |
78 | | #include "key/lib.h" |
79 | | #include "menu/lib.h" |
80 | | #include "attach.h" |
81 | | #include "attachments.h" |
82 | | #include "format_flags.h" |
83 | | #include "functions.h" |
84 | | #include "hdrline.h" |
85 | | #include "hook.h" |
86 | | #include "mutt_logging.h" |
87 | | #include "muttlib.h" |
88 | | #include "mview.h" |
89 | | #include "private_data.h" |
90 | | #include "recvattach.h" |
91 | | |
92 | | /// Help Bar for the Attachment selection dialog |
93 | | static const struct Mapping AttachmentHelp[] = { |
94 | | // clang-format off |
95 | | { N_("Exit"), OP_EXIT }, |
96 | | { N_("Save"), OP_ATTACHMENT_SAVE }, |
97 | | { N_("Pipe"), OP_PIPE }, |
98 | | { N_("Print"), OP_ATTACHMENT_PRINT }, |
99 | | { N_("Help"), OP_HELP }, |
100 | | { NULL, 0 }, |
101 | | // clang-format on |
102 | | }; |
103 | | |
104 | | /** |
105 | | * attach_config_observer - Notification that a Config Variable has changed - Implements ::observer_t - @ingroup observer_api |
106 | | * |
107 | | * The Address Book Window is affected by changes to `$sort_attach`. |
108 | | */ |
109 | | static int attach_config_observer(struct NotifyCallback *nc) |
110 | 0 | { |
111 | 0 | if (nc->event_type != NT_CONFIG) |
112 | 0 | return 0; |
113 | 0 | if (!nc->global_data || !nc->event_data) |
114 | 0 | return -1; |
115 | | |
116 | 0 | struct EventConfig *ev_c = nc->event_data; |
117 | |
|
118 | 0 | if (!mutt_str_equal(ev_c->name, "attach_format") && !mutt_str_equal(ev_c->name, "message_format")) |
119 | 0 | return 0; |
120 | | |
121 | 0 | struct Menu *menu = nc->global_data; |
122 | 0 | menu_queue_redraw(menu, MENU_REDRAW_FULL); |
123 | 0 | mutt_debug(LL_DEBUG5, "config done, request WA_RECALC, MENU_REDRAW_FULL\n"); |
124 | |
|
125 | 0 | return 0; |
126 | 0 | } |
127 | | |
128 | | /** |
129 | | * attach_format_str - Format a string for the attachment menu - Implements ::format_t - @ingroup expando_api |
130 | | * |
131 | | * | Expando | Description |
132 | | * | :------ | :------------------------------------------------------- |
133 | | * | \%C | Character set |
134 | | * | \%c | Character set: convert? |
135 | | * | \%D | Deleted flag |
136 | | * | \%d | Description |
137 | | * | \%e | MIME content-transfer-encoding |
138 | | * | \%f | Filename |
139 | | * | \%F | Filename for content-disposition header |
140 | | * | \%I | Content-disposition, either I (inline) or A (attachment) |
141 | | * | \%m | Major MIME type |
142 | | * | \%M | MIME subtype |
143 | | * | \%n | Attachment number |
144 | | * | \%Q | 'Q', if MIME part qualifies for attachment counting |
145 | | * | \%s | Size |
146 | | * | \%t | Tagged flag |
147 | | * | \%T | Tree chars |
148 | | * | \%u | Unlink |
149 | | * | \%X | Number of qualifying MIME parts in this part and its children |
150 | | */ |
151 | | const char *attach_format_str(char *buf, size_t buflen, size_t col, int cols, char op, |
152 | | const char *src, const char *prec, const char *if_str, |
153 | | const char *else_str, intptr_t data, MuttFormatFlags flags) |
154 | 0 | { |
155 | 0 | char fmt[128] = { 0 }; |
156 | 0 | char charset[128] = { 0 }; |
157 | 0 | struct AttachPtr *aptr = (struct AttachPtr *) data; |
158 | 0 | bool optional = (flags & MUTT_FORMAT_OPTIONAL); |
159 | |
|
160 | 0 | switch (op) |
161 | 0 | { |
162 | 0 | case 'C': |
163 | 0 | if (!optional) |
164 | 0 | { |
165 | 0 | if (mutt_is_text_part(aptr->body) && |
166 | 0 | mutt_body_get_charset(aptr->body, charset, sizeof(charset))) |
167 | 0 | { |
168 | 0 | mutt_format_s(buf, buflen, prec, charset); |
169 | 0 | } |
170 | 0 | else |
171 | 0 | { |
172 | 0 | mutt_format_s(buf, buflen, prec, ""); |
173 | 0 | } |
174 | 0 | } |
175 | 0 | else if (!mutt_is_text_part(aptr->body) || |
176 | 0 | !mutt_body_get_charset(aptr->body, charset, sizeof(charset))) |
177 | 0 | { |
178 | 0 | optional = false; |
179 | 0 | } |
180 | 0 | break; |
181 | 0 | case 'c': |
182 | | /* XXX */ |
183 | 0 | if (!optional) |
184 | 0 | { |
185 | 0 | snprintf(fmt, sizeof(fmt), "%%%sc", prec); |
186 | 0 | snprintf(buf, buflen, fmt, |
187 | 0 | ((aptr->body->type != TYPE_TEXT) || aptr->body->noconv) ? 'n' : 'c'); |
188 | 0 | } |
189 | 0 | else if ((aptr->body->type != TYPE_TEXT) || aptr->body->noconv) |
190 | 0 | { |
191 | 0 | optional = false; |
192 | 0 | } |
193 | 0 | break; |
194 | 0 | case 'd': |
195 | 0 | { |
196 | 0 | const char *const c_message_format = cs_subset_string(NeoMutt->sub, "message_format"); |
197 | 0 | if (!optional) |
198 | 0 | { |
199 | 0 | if (aptr->body->description) |
200 | 0 | { |
201 | 0 | mutt_format_s(buf, buflen, prec, aptr->body->description); |
202 | 0 | break; |
203 | 0 | } |
204 | 0 | if (mutt_is_message_type(aptr->body->type, aptr->body->subtype) && |
205 | 0 | c_message_format && aptr->body->email) |
206 | 0 | { |
207 | 0 | char s[128] = { 0 }; |
208 | 0 | mutt_make_string(s, sizeof(s), cols, c_message_format, NULL, -1, |
209 | 0 | aptr->body->email, |
210 | 0 | MUTT_FORMAT_FORCESUBJ | MUTT_FORMAT_ARROWCURSOR, NULL); |
211 | 0 | if (*s) |
212 | 0 | { |
213 | 0 | mutt_format_s(buf, buflen, prec, s); |
214 | 0 | break; |
215 | 0 | } |
216 | 0 | } |
217 | 0 | if (!aptr->body->d_filename && !aptr->body->filename) |
218 | 0 | { |
219 | 0 | mutt_format_s(buf, buflen, prec, "<no description>"); |
220 | 0 | break; |
221 | 0 | } |
222 | 0 | } |
223 | 0 | else if (aptr->body->description || |
224 | 0 | (mutt_is_message_type(aptr->body->type, aptr->body->subtype) && |
225 | 0 | c_message_format && aptr->body->email)) |
226 | 0 | { |
227 | 0 | break; |
228 | 0 | } |
229 | 0 | } |
230 | | /* fallthrough */ |
231 | 0 | case 'F': |
232 | 0 | if (!optional) |
233 | 0 | { |
234 | 0 | if (aptr->body->d_filename) |
235 | 0 | { |
236 | 0 | mutt_format_s(buf, buflen, prec, aptr->body->d_filename); |
237 | 0 | break; |
238 | 0 | } |
239 | 0 | } |
240 | 0 | else if (!aptr->body->d_filename && !aptr->body->filename) |
241 | 0 | { |
242 | 0 | optional = false; |
243 | 0 | break; |
244 | 0 | } |
245 | | /* fallthrough */ |
246 | 0 | case 'f': |
247 | 0 | if (!optional) |
248 | 0 | { |
249 | 0 | if (aptr->body->filename && (*aptr->body->filename == '/')) |
250 | 0 | { |
251 | 0 | struct Buffer *path = buf_pool_get(); |
252 | |
|
253 | 0 | buf_strcpy(path, aptr->body->filename); |
254 | 0 | buf_pretty_mailbox(path); |
255 | 0 | mutt_format_s(buf, buflen, prec, buf_string(path)); |
256 | 0 | buf_pool_release(&path); |
257 | 0 | } |
258 | 0 | else |
259 | 0 | { |
260 | 0 | mutt_format_s(buf, buflen, prec, NONULL(aptr->body->filename)); |
261 | 0 | } |
262 | 0 | } |
263 | 0 | else if (!aptr->body->filename) |
264 | 0 | { |
265 | 0 | optional = false; |
266 | 0 | } |
267 | 0 | break; |
268 | 0 | case 'D': |
269 | 0 | if (!optional) |
270 | 0 | snprintf(buf, buflen, "%c", aptr->body->deleted ? 'D' : ' '); |
271 | 0 | else if (!aptr->body->deleted) |
272 | 0 | optional = false; |
273 | 0 | break; |
274 | 0 | case 'e': |
275 | 0 | if (!optional) |
276 | 0 | mutt_format_s(buf, buflen, prec, ENCODING(aptr->body->encoding)); |
277 | 0 | break; |
278 | 0 | case 'I': |
279 | 0 | if (optional) |
280 | 0 | break; |
281 | | |
282 | 0 | const char dispchar[] = { 'I', 'A', 'F', '-' }; |
283 | 0 | char ch; |
284 | |
|
285 | 0 | if (aptr->body->disposition < sizeof(dispchar)) |
286 | 0 | { |
287 | 0 | ch = dispchar[aptr->body->disposition]; |
288 | 0 | } |
289 | 0 | else |
290 | 0 | { |
291 | 0 | mutt_debug(LL_DEBUG1, "ERROR: invalid content-disposition %d\n", |
292 | 0 | aptr->body->disposition); |
293 | 0 | ch = '!'; |
294 | 0 | } |
295 | 0 | snprintf(buf, buflen, "%c", ch); |
296 | 0 | break; |
297 | 0 | case 'm': |
298 | 0 | if (!optional) |
299 | 0 | mutt_format_s(buf, buflen, prec, TYPE(aptr->body)); |
300 | 0 | break; |
301 | 0 | case 'M': |
302 | 0 | if (!optional) |
303 | 0 | mutt_format_s(buf, buflen, prec, aptr->body->subtype); |
304 | 0 | else if (!aptr->body->subtype) |
305 | 0 | optional = false; |
306 | 0 | break; |
307 | 0 | case 'n': |
308 | 0 | if (optional) |
309 | 0 | break; |
310 | | |
311 | 0 | snprintf(fmt, sizeof(fmt), "%%%sd", prec); |
312 | 0 | snprintf(buf, buflen, fmt, aptr->num + 1); |
313 | 0 | break; |
314 | 0 | case 'Q': |
315 | 0 | if (optional) |
316 | 0 | { |
317 | 0 | optional = aptr->body->attach_qualifies; |
318 | 0 | } |
319 | 0 | else |
320 | 0 | { |
321 | 0 | snprintf(fmt, sizeof(fmt), "%%%sc", prec); |
322 | 0 | mutt_format_s(buf, buflen, fmt, "Q"); |
323 | 0 | } |
324 | 0 | break; |
325 | 0 | case 's': |
326 | 0 | { |
327 | 0 | size_t l = 0; |
328 | 0 | if (aptr->body->filename && (flags & MUTT_FORMAT_STAT_FILE)) |
329 | 0 | { |
330 | 0 | l = mutt_file_get_size(aptr->body->filename); |
331 | 0 | } |
332 | 0 | else |
333 | 0 | { |
334 | 0 | l = aptr->body->length; |
335 | 0 | } |
336 | |
|
337 | 0 | if (!optional) |
338 | 0 | { |
339 | 0 | char tmp[128] = { 0 }; |
340 | 0 | mutt_str_pretty_size(tmp, sizeof(tmp), l); |
341 | 0 | mutt_format_s(buf, buflen, prec, tmp); |
342 | 0 | } |
343 | 0 | else if (l == 0) |
344 | 0 | { |
345 | 0 | optional = false; |
346 | 0 | } |
347 | |
|
348 | 0 | break; |
349 | 0 | } |
350 | 0 | case 't': |
351 | 0 | if (!optional) |
352 | 0 | snprintf(buf, buflen, "%c", aptr->body->tagged ? '*' : ' '); |
353 | 0 | else if (!aptr->body->tagged) |
354 | 0 | optional = false; |
355 | 0 | break; |
356 | 0 | case 'T': |
357 | 0 | if (!optional) |
358 | 0 | mutt_format_s_tree(buf, buflen, prec, NONULL(aptr->tree)); |
359 | 0 | else if (!aptr->tree) |
360 | 0 | optional = false; |
361 | 0 | break; |
362 | 0 | case 'u': |
363 | 0 | if (!optional) |
364 | 0 | snprintf(buf, buflen, "%c", aptr->body->unlink ? '-' : ' '); |
365 | 0 | else if (!aptr->body->unlink) |
366 | 0 | optional = false; |
367 | 0 | break; |
368 | 0 | case 'X': |
369 | 0 | if (optional) |
370 | 0 | { |
371 | 0 | optional = ((aptr->body->attach_count + aptr->body->attach_qualifies) != 0); |
372 | 0 | } |
373 | 0 | else |
374 | 0 | { |
375 | 0 | snprintf(fmt, sizeof(fmt), "%%%sd", prec); |
376 | 0 | snprintf(buf, buflen, fmt, aptr->body->attach_count + aptr->body->attach_qualifies); |
377 | 0 | } |
378 | 0 | break; |
379 | 0 | default: |
380 | 0 | *buf = '\0'; |
381 | 0 | } |
382 | | |
383 | 0 | if (optional) |
384 | 0 | { |
385 | 0 | mutt_expando_format(buf, buflen, col, cols, if_str, attach_format_str, data, |
386 | 0 | MUTT_FORMAT_NO_FLAGS); |
387 | 0 | } |
388 | 0 | else if (flags & MUTT_FORMAT_OPTIONAL) |
389 | 0 | { |
390 | 0 | mutt_expando_format(buf, buflen, col, cols, else_str, attach_format_str, |
391 | 0 | data, MUTT_FORMAT_NO_FLAGS); |
392 | 0 | } |
393 | | |
394 | | /* We return the format string, unchanged */ |
395 | 0 | return src; |
396 | 0 | } |
397 | | |
398 | | /** |
399 | | * attach_make_entry - Format a menu item for the attachment list - Implements Menu::make_entry() - @ingroup menu_make_entry |
400 | | * |
401 | | * @sa $attach_format, attach_format_str() |
402 | | */ |
403 | | static void attach_make_entry(struct Menu *menu, char *buf, size_t buflen, int line) |
404 | 0 | { |
405 | 0 | struct AttachPrivateData *priv = menu->mdata; |
406 | 0 | struct AttachCtx *actx = priv->actx; |
407 | |
|
408 | 0 | const char *const c_attach_format = cs_subset_string(NeoMutt->sub, "attach_format"); |
409 | 0 | mutt_expando_format(buf, buflen, 0, menu->win->state.cols, NONULL(c_attach_format), |
410 | 0 | attach_format_str, (intptr_t) (actx->idx[actx->v2r[line]]), |
411 | 0 | MUTT_FORMAT_ARROWCURSOR); |
412 | 0 | } |
413 | | |
414 | | /** |
415 | | * attach_tag - Tag an attachment - Implements Menu::tag() - @ingroup menu_tag |
416 | | */ |
417 | | static int attach_tag(struct Menu *menu, int sel, int act) |
418 | 0 | { |
419 | 0 | struct AttachPrivateData *priv = menu->mdata; |
420 | 0 | struct AttachCtx *actx = priv->actx; |
421 | |
|
422 | 0 | struct Body *cur = actx->idx[actx->v2r[sel]]->body; |
423 | 0 | bool ot = cur->tagged; |
424 | |
|
425 | 0 | cur->tagged = ((act >= 0) ? act : !cur->tagged); |
426 | 0 | return cur->tagged - ot; |
427 | 0 | } |
428 | | |
429 | | /** |
430 | | * attach_window_observer - Notification that a Window has changed - Implements ::observer_t - @ingroup observer_api |
431 | | * |
432 | | * This function is triggered by changes to the windows. |
433 | | * |
434 | | * - Delete (this window): clean up the resources held by the Help Bar |
435 | | */ |
436 | | static int attach_window_observer(struct NotifyCallback *nc) |
437 | 0 | { |
438 | 0 | if (nc->event_type != NT_WINDOW) |
439 | 0 | return 0; |
440 | 0 | if (!nc->global_data || !nc->event_data) |
441 | 0 | return -1; |
442 | 0 | if (nc->event_subtype != NT_WINDOW_DELETE) |
443 | 0 | return 0; |
444 | | |
445 | 0 | struct MuttWindow *win_menu = nc->global_data; |
446 | 0 | struct EventWindow *ev_w = nc->event_data; |
447 | 0 | if (ev_w->win != win_menu) |
448 | 0 | return 0; |
449 | | |
450 | 0 | struct Menu *menu = win_menu->wdata; |
451 | |
|
452 | 0 | notify_observer_remove(NeoMutt->sub->notify, attach_config_observer, menu); |
453 | 0 | notify_observer_remove(win_menu->notify, attach_window_observer, win_menu); |
454 | |
|
455 | 0 | mutt_debug(LL_DEBUG5, "window delete done\n"); |
456 | 0 | return 0; |
457 | 0 | } |
458 | | |
459 | | /** |
460 | | * dlg_attachment - Show the attachments in a Menu - @ingroup gui_dlg |
461 | | * @param sub Config Subset |
462 | | * @param mv Mailbox view |
463 | | * @param e Email |
464 | | * @param fp File with the content of the email, or NULL |
465 | | * @param attach_msg Are we in "attach message" mode? |
466 | | * |
467 | | * The Select Attachment dialog shows an Email's attachments. |
468 | | * They can be viewed using the Pager or Mailcap programs. |
469 | | * They can also be saved, printed, deleted, etc. |
470 | | */ |
471 | | void dlg_attachment(struct ConfigSubset *sub, struct MailboxView *mv, |
472 | | struct Email *e, FILE *fp, bool attach_msg) |
473 | 0 | { |
474 | 0 | if (!mv || !mv->mailbox || !e || !fp) |
475 | 0 | return; |
476 | | |
477 | 0 | struct Mailbox *m = mv->mailbox; |
478 | | |
479 | | /* make sure we have parsed this message */ |
480 | 0 | mutt_parse_mime_message(e, fp); |
481 | 0 | mutt_message_hook(m, e, MUTT_MESSAGE_HOOK); |
482 | |
|
483 | 0 | struct MuttWindow *dlg = simple_dialog_new(MENU_ATTACHMENT, WT_DLG_ATTACHMENT, AttachmentHelp); |
484 | 0 | struct Menu *menu = dlg->wdata; |
485 | 0 | menu->make_entry = attach_make_entry; |
486 | 0 | menu->tag = attach_tag; |
487 | |
|
488 | 0 | struct AttachCtx *actx = mutt_actx_new(); |
489 | 0 | actx->email = e; |
490 | 0 | actx->fp_root = fp; |
491 | 0 | mutt_update_recvattach_menu(actx, menu, true); |
492 | |
|
493 | 0 | struct AttachPrivateData *priv = attach_private_data_new(); |
494 | 0 | priv->menu = menu; |
495 | 0 | priv->actx = actx; |
496 | 0 | priv->sub = sub; |
497 | 0 | priv->mailbox = m; |
498 | 0 | priv->attach_msg = attach_msg; |
499 | 0 | menu->mdata = priv; |
500 | 0 | menu->mdata_free = attach_private_data_free; |
501 | | |
502 | | // NT_COLOR is handled by the SimpleDialog |
503 | 0 | notify_observer_add(NeoMutt->sub->notify, NT_CONFIG, attach_config_observer, menu); |
504 | 0 | notify_observer_add(menu->win->notify, NT_WINDOW, attach_window_observer, menu->win); |
505 | |
|
506 | 0 | struct MuttWindow *sbar = window_find_child(dlg, WT_STATUS_BAR); |
507 | 0 | sbar_set_title(sbar, _("Attachments")); |
508 | |
|
509 | 0 | struct MuttWindow *old_focus = window_set_focus(menu->win); |
510 | | // --------------------------------------------------------------------------- |
511 | | // Event Loop |
512 | 0 | int rc = 0; |
513 | 0 | int op = OP_NULL; |
514 | 0 | do |
515 | 0 | { |
516 | 0 | menu_tagging_dispatcher(menu->win, op); |
517 | 0 | window_redraw(NULL); |
518 | |
|
519 | 0 | op = km_dokey(MENU_ATTACHMENT, GETCH_NO_FLAGS); |
520 | 0 | mutt_debug(LL_DEBUG1, "Got op %s (%d)\n", opcodes_get_name(op), op); |
521 | 0 | if (op < 0) |
522 | 0 | continue; |
523 | 0 | if (op == OP_NULL) |
524 | 0 | { |
525 | 0 | km_error_key(MENU_ATTACHMENT); |
526 | 0 | continue; |
527 | 0 | } |
528 | 0 | mutt_clear_error(); |
529 | |
|
530 | 0 | rc = attach_function_dispatcher(dlg, op); |
531 | 0 | if (rc == FR_UNKNOWN) |
532 | 0 | rc = menu_function_dispatcher(menu->win, op); |
533 | 0 | if (rc == FR_UNKNOWN) |
534 | 0 | rc = global_function_dispatcher(NULL, op); |
535 | |
|
536 | 0 | if (rc == FR_CONTINUE) |
537 | 0 | { |
538 | 0 | op = priv->op; |
539 | 0 | } |
540 | |
|
541 | 0 | } while (rc != FR_DONE); |
542 | | // --------------------------------------------------------------------------- |
543 | | |
544 | 0 | window_set_focus(old_focus); |
545 | 0 | simple_dialog_free(&dlg); |
546 | 0 | } |