35 #include <FL/Enumerations.H>
37 #if !defined FL_ABI_VERSION && defined FLTK_ABI_VERSION
38 # define FL_ABI_VERSION FLTK_ABI_VERSION
41 #include <FL/Fl_Box.H>
42 #include <FL/Fl_Button.H>
43 #include <FL/Fl_Check_Button.H>
44 #include <FL/Fl_Hold_Browser.H>
45 #include <FL/Fl_File_Chooser.H>
46 #include <FL/Fl_Group.H>
47 #include <FL/Fl_Input.H>
48 #include <FL/Fl_Input_Choice.H>
49 #include <FL/Fl_Menu_.H>
50 #include <FL/Fl_Menu_Bar.H>
51 #include <FL/Fl_Menu_Item.H>
52 #include <FL/Fl_Pixmap.H>
53 #include <FL/Fl_PostScript.H>
54 #include <FL/Fl_Progress.H>
55 #include <FL/Fl_Printer.H>
56 #include <FL/Fl_Radio_Round_Button.H>
57 #include <FL/Fl_Return_Button.H>
58 #include <FL/Fl_Sys_Menu_Bar.H>
59 #include <FL/Fl_Text_Buffer.H>
60 #include <FL/Fl_Text_Display.H>
61 #include <FL/Fl_Text_Editor.H>
62 #include <FL/Fl_Tabs.H>
63 #include <FL/Fl_Tile.H>
64 #include <FL/Fl_Tree_Item.H>
65 #include <FL/Fl_Tree.H>
66 #include <FL/Fl_Widget.H>
67 #if CFG_DB_DISABLE // Double buffered windows are slow, use only on request
68 # include <FL/Fl_Window.H>
69 #else // CFG_DB_DISABLE
70 # include <FL/Fl_Double_Window.H>
71 #endif // CFG_DB_DISABLE
72 #include <FL/fl_ask.H>
113 #define USE_LINE_COUNT 0
116 #define USE_ARTICLE_NUMBER 0
123 #define MAIN_ERR_PREFIX "GUI: "
130 #define UI_COLOR_MENU_SELECTION (Fl_Color) 0x50505000UL
132 #define UI_COLOR_PROGRESS_BAR (Fl_Color) 0x50505000UL
134 #define UI_COLOR_RADIO_BUTTON (Fl_Color) 0x50505000UL
138 #define UI_STYLES_LEN 9
142 #define UI_CB_START 0
143 #define UI_CB_CONTINUE 1
144 #define UI_CB_FINISH 2
149 #define UI_CB_COOKIE_SERVER 0U
150 #define UI_CB_COOKIE_GROUPLIST 1U
151 #define UI_CB_COOKIE_GROUPLABELS 2U
152 #define UI_CB_COOKIE_GROUPPROPOSAL 3U
153 #define UI_CB_COOKIE_GROUPINFO1 4U
154 #define UI_CB_COOKIE_GROUPINFO2 5U
155 #define UI_CB_COOKIE_GROUP 6U
156 #define UI_CB_COOKIE_OVERVIEW 7U
157 #define UI_CB_COOKIE_HEADER 8U
158 #define UI_CB_COOKIE_BODY 9U
159 #define UI_CB_COOKIE_MOTD 10U
160 #define UI_CB_COOKIE_ARTICLE 11U
161 #define UI_CB_COOKIE_SRC 12U
162 #define UI_CB_COOKIE_POST 13U
170 #define UI_ENC_NONE 0 // No encryption
171 #define UI_ENC_STRONG 1 // TLS with strong encryption and forward secrecy
172 #define UI_ENC_WEAK 2 // TLS compatibility mode offering weak cipher suites
177 #define UI_AUTH_NONE 0 // No authentication
178 #define UI_AUTH_USER 1 // AUTHINFO USER/PASS as defined in RFC 4643
183 #define UI_CAC_MIN 10 // Lower limit: 1
184 #define UI_CAC_MAX 50000 // Upper limit: INT_MAX
188 #define UI_HDR_BUFSIZE (std::size_t) 998
191 #define UI_STATIC_STYLE_BUFSIZE (std::size_t) 80
194 #define UI_XPOST_LIMIT (std::size_t) 10
200 #define UI_AW_REFERENCES 0
204 # define UI_WINDOW_CLASS Fl_Window
205 #else // CFG_DB_DISABLE
206 # define UI_WINDOW_CLASS Fl_Double_Window
207 #endif // CFG_DB_DISABLE
210 #define USE_WINDOW_ICON 0
211 #ifdef FL_ABI_VERSION
212 # if 10303 <= FL_ABI_VERSION
214 # undef USE_WINDOW_ICON
215 # define USE_WINDOW_ICON 1
216 # endif // 10303 <= FL_ABI_VERSION
217 #endif // FL_ABI_VERSION
241 inline void serverReplace(
const char* s)
243 std::strncpy(server, s, 128); server[127] = 0;
245 inline void serviceReplace(
const char* s)
247 std::strncpy(service, s, 6); service[5] = 0;
249 inline void serviceReplace(
unsigned int i)
251 std::ostringstream ss;
253 if(0xFFFFU < i) { i = 0xFFFFU; }
254 ss << i << std::flush;
255 const std::string& s = ss.str();
256 std::strncpy(service, s.c_str(), 6); service[5] = 0;
263 struct MIMEContentListElement
270 const char* filename;
271 MIMEContentListElement* next;
277 MIMEContentListElement* partList;
279 const char* createMessageHeader(
const char*, std::size_t);
280 MIMEContentListElement* decodeElement(
const char*, std::size_t,
char*,
281 bool,
bool, std::size_t*);
282 MIMEContentListElement* initElement(
const char*, std::size_t,
286 inline bool is_multipart(
void) {
return(multipart); }
287 inline std::size_t parts(
void) {
return(partNum); }
288 inline const char* part_header(std::size_t i)
290 MIMEContentListElement* mcle = partList;
292 if(!partNum || i >= partNum) {
return(NULL); }
295 while(i--) { mcle = mcle->next; }
296 return(mcle->header);
299 inline const char* part(std::size_t i,
enc_mime_cte* te,
302 MIMEContentListElement* mcle = partList;
304 if(!partNum || i >= partNum) {
return(NULL); }
307 while(i--) { mcle = mcle->next; }
309 if(NULL != ctp) { *ctp = &mcle->ct; }
310 return(mcle->content);
315 MIMEContentListElement* mcle = partList;
317 if(!partNum || i >= partNum) {
return(ENC_CD_UNKNOWN); }
320 while(i--) { mcle = mcle->next; }
324 inline const char* filename(std::size_t i)
326 MIMEContentListElement* mcle = partList;
328 if(!partNum || i >= partNum) {
return(NULL); }
331 while(i--) { mcle = mcle->next; }
332 return(mcle->filename);
340 class My_Text_Display :
public Fl_Text_Display
347 My_Text_Display(
int X,
int Y,
int W,
int H,
const char* L = 0)
348 : Fl_Text_Display(X, Y, W, H, L) { linkPushed = -1; }
352 class My_Tree :
public Fl_Tree
356 bool positions_recalculated;
357 Fl_Tree_Item* current_article;
361 inline void update_in_progress(
bool state) { updated = !state; }
362 inline bool update_in_progress(
void) {
return !updated; }
363 inline void not_drawn(
void) { positions_recalculated =
false; }
364 inline bool drawn(
void)
367 if (0 == w() || 0 == h()) {
return true; }
368 return(positions_recalculated);
370 inline void draw(
void)
374 positions_recalculated =
true;
376 inline void store_current(Fl_Tree_Item* ti)
378 current_article = ti;
380 inline void select_former(
void)
382 if(NULL != current_article)
384 set_item_focus(current_article);
385 select_only(current_article, 0);
388 My_Tree(
int X,
int Y,
int W,
int H,
const char* L = 0)
389 : Fl_Tree(X, Y, W, H, L)
392 positions_recalculated =
false;
393 current_article = NULL;
398 class ServerCfgWindow :
public UI_WINDOW_CLASS
405 Fl_Input* scfgHostname;
406 Fl_Input* scfgService;
407 Fl_Radio_Round_Button* scfgTlsOff;
408 Fl_Radio_Round_Button* scfgTlsStrong;
409 Fl_Radio_Round_Button* scfgTlsWeak;
410 Fl_Radio_Round_Button* scfgAuthOff;
411 Fl_Radio_Round_Button* scfgAuthUser;
417 inline void ok_cb_i(
void) { finished = 1; }
418 static void ok_cb(Fl_Widget*,
void* w)
420 ((ServerCfgWindow*) w)->ok_cb_i();
424 inline void cancel_cb_i(
void) { finished = -1; }
425 static void cancel_cb(Fl_Widget*,
void* w)
427 ((ServerCfgWindow*) w)->cancel_cb_i();
431 inline void enc_cb_i(
bool enc)
435 scfgService->value(
"nntp");
436 #if !CFG_NNTP_AUTH_UNENCRYPTED
437 scfgAuthOff->setonly();
438 grpAuth->deactivate();
443 scfgService->value(
"nntps");
447 static void enc_off_cb(Fl_Widget*,
void* w)
449 ((ServerCfgWindow*) w)->enc_cb_i(
false);
451 static void enc_on_cb(Fl_Widget*,
void* w)
453 ((ServerCfgWindow*) w)->enc_cb_i(
true);
458 ServerCfgWindow(ServerConfig*,
const char*);
459 ~ServerCfgWindow(
void);
463 class IdentityCfgWindow :
public UI_WINDOW_CLASS
469 Fl_Input* replytoName;
470 Fl_Input* replytoEmail;
473 inline void ok_cb_i(
void);
474 static void ok_cb(Fl_Widget*,
void* w)
476 ((IdentityCfgWindow*) w)->ok_cb_i();
480 static void cancel_cb(Fl_Widget*,
void* w)
482 Fl::delete_widget((Fl_Widget*) w);
485 IdentityCfgWindow(
const char*);
486 ~IdentityCfgWindow(
void);
490 class MiscCfgWindow :
public UI_WINDOW_CLASS
496 Fl_Check_Button* cmprEnable;
497 Fl_Check_Button* localTime;
498 Fl_Check_Button* uagentEnable;
500 Fl_Check_Button* qsSpace;
501 Fl_Check_Button* qsUnify;
504 inline void ok_cb_i(
void);
505 static void ok_cb(Fl_Widget*,
void* w)
507 ((MiscCfgWindow*) w)->ok_cb_i();
511 static void cancel_cb(Fl_Widget*,
void* w)
513 Fl::delete_widget((Fl_Widget*) w);
516 MiscCfgWindow(
const char*);
517 ~MiscCfgWindow(
void);
522 class SearchWindow :
public UI_WINDOW_CLASS
525 Fl_Input* searchField;
526 Fl_Check_Button* cisEnable;
527 const char** currentSearchString;
530 inline void ok_cb_i(
void);
531 static void ok_cb(Fl_Widget*,
void* w)
533 ((SearchWindow*) w)->ok_cb_i();
534 ((SearchWindow*) w)->finished = 1;
538 static void cancel_cb(Fl_Widget*,
void* w)
540 ((SearchWindow*) w)->finished = -1;
544 SearchWindow(
const char*,
const char**);
550 class ProtocolConsole :
public UI_WINDOW_CLASS
553 Fl_Text_Display* consoleDisplay;
555 Fl_Text_Buffer* consoleText;
560 static void exit_cb(Fl_Widget*,
void* w)
562 Fl::delete_widget((Fl_Widget*) w);
567 ProtocolConsole(
const char*);
568 ~ProtocolConsole(
void);
572 class SubscribeWindow :
public UI_WINDOW_CLASS
575 Fl_Group* subscribeGroup;
576 Fl_Tree* subscribeTree;
581 inline void ok_cb_i(
void);
582 static void ok_cb(Fl_Widget*,
void* w)
584 ((SubscribeWindow*) w)->ok_cb_i();
588 static void cancel_cb(Fl_Widget*,
void* w)
590 Fl::delete_widget((Fl_Widget*) w);
594 inline void tree_cb_i(
void)
598 if(FL_TREE_REASON_SELECTED == subscribeTree->callback_reason())
601 ti = subscribeTree->callback_item();
602 if(NULL == ti->user_data()) { subscribeTree->deselect(ti, 0); }
605 static void tree_cb(Fl_Widget*,
void* w)
607 ((SubscribeWindow*) w)->tree_cb_i();
610 inline void add(
const char* entry,
core_anum_t num,
const char* label)
613 std::ostringstream labelString;
615 ti = subscribeTree->find_item(entry);
616 if(NULL == ti) { ti = subscribeTree->add(entry); }
619 PRINT_ERROR(
"Adding group to subscription tree failed");
624 ti->labelfont(FL_HELVETICA_BOLD);
625 ti->user_data((
void*) entry);
626 labelString << ti->label() <<
" (" << num <<
")";
627 if(NULL != label) { labelString <<
" | " << label; }
638 const std::string& ls = labelString.str();
639 ti->label(ls.c_str());
642 inline void collapseAll(
void)
646 for(i = subscribeTree->first(); i; i = subscribeTree->next(i))
648 subscribeTree->close(i, 0);
650 subscribeTree->open(subscribeTree->root(), 0);
654 ~SubscribeWindow(
void);
658 class MIDSearchWindow :
public UI_WINDOW_CLASS
665 inline void ok_cb_i(
void);
666 static void ok_cb(Fl_Widget*,
void* w)
668 ((MIDSearchWindow*) w)->ok_cb_i();
672 static void cancel_cb(Fl_Widget*,
void* w)
674 Fl::delete_widget((Fl_Widget*) w);
677 MIDSearchWindow(
const char*);
678 ~MIDSearchWindow(
void);
682 class BugreportWindow :
public UI_WINDOW_CLASS
685 Fl_Text_Display* bugreportDisplay;
686 Fl_Text_Buffer* bugreportText;
689 static void exit_cb(Fl_Widget*,
void* w)
691 Fl::delete_widget((Fl_Widget*) w);
695 BugreportWindow(
const char*,
const char*);
696 ~BugreportWindow(
void);
700 class LicenseWindow :
public UI_WINDOW_CLASS
703 Fl_Text_Display* licenseDisplay;
704 Fl_Text_Buffer* licenseText;
707 static void exit_cb(Fl_Widget*,
void* w)
709 Fl::delete_widget((Fl_Widget*) w);
713 LicenseWindow(
const char*);
714 ~LicenseWindow(
void);
718 class MotdWindow :
public UI_WINDOW_CLASS
721 Fl_Text_Display* motdDisplay;
722 Fl_Text_Buffer* motdText;
725 static void exit_cb(Fl_Widget*,
void* w)
727 Fl::delete_widget((Fl_Widget*) w);
731 MotdWindow(
const char*,
const char*);
736 class ArticleWindow :
public UI_WINDOW_CLASS
739 Fl_Group* articleGroup;
740 My_Text_Display* articleDisplay;
741 Fl_Text_Buffer* articleText;
742 Fl_Text_Buffer* articleStyle;
743 Fl_Text_Display::Style_Table_Entry* styles;
745 MIMEContent* mimeData;
749 void articleUpdate(Fl_Text_Buffer* article);
752 static void cancel_cb(Fl_Widget*,
void* w)
754 Fl::delete_widget((Fl_Widget*) w);
758 ArticleWindow(
const char*,
const char*);
759 ~ArticleWindow(
void);
763 class ArticleSrcWindow :
public UI_WINDOW_CLASS
767 Fl_Text_Display* srcDisplay;
768 Fl_Text_Buffer* srcText;
769 Fl_Text_Buffer* srcStyle;
770 Fl_Text_Display::Style_Table_Entry* styles;
772 const char* pathname;
775 inline void save_cb_i(
void);
776 static void save_cb(Fl_Widget*,
void* w)
778 ((ArticleSrcWindow*) w)->save_cb_i();
782 static void cancel_cb(Fl_Widget*,
void* w)
784 Fl::delete_widget((Fl_Widget*) w);
788 ArticleSrcWindow(
const char*,
const char*);
789 ~ArticleSrcWindow(
void);
793 class ComposeWindow :
public UI_WINDOW_CLASS
797 Fl_Group* subjectGroup;
798 Fl_Input* subjectField;
800 Fl_Group* uriEncGroup;
801 Fl_Group* advancedGroup;
802 Fl_Text_Buffer* compHeader;
803 Fl_Text_Display::Style_Table_Entry* styles;
804 Fl_Text_Buffer* currentStyle;
805 Fl_Text_Buffer* compText;
807 Fl_Box* uriHeaderField;
808 Fl_Input_Choice* uriSchemeField;
809 Fl_Input* uriBodyField;
811 Fl_Input* newsgroupsField;
812 Fl_Input_Choice* fup2Field;
813 Fl_Input_Choice* keywordField;
814 Fl_Input* expireField;
815 Fl_Input_Choice* distriField;
816 Fl_Check_Button* archiveButton;
820 inline void change_cb_i(Fl_Widget* w);
821 static void change_cb(Fl_Widget*,
void* w)
823 ((ComposeWindow*) w)->change_cb_i((Fl_Widget*) w);
827 inline void style_update_cb_i(
int pos,
int nInserted,
int nDeleted,
828 int nRestyled,
const char* deletedText,
829 Fl_Text_Buffer* style,
830 Fl_Text_Editor* editor);
831 static void style_update_cb(
int pos,
int nInserted,
int nDeleted,
832 int nRestyled,
const char* deletedText,
836 ->style_update_cb_i(pos, nInserted, nDeleted, nRestyled, deletedText,
837 ((ComposeWindow*) w)->currentStyle,
838 ((ComposeWindow*) w)->compEditor);
843 inline void send_cb_i(Fl_Widget* w);
844 static void send_cb(Fl_Widget*,
void* w)
846 ((ComposeWindow*) w)->send_cb_i((Fl_Widget*) w);
850 inline void cancel_cb_i(Fl_Widget*);
851 static void cancel_cb(Fl_Widget*,
void* w)
853 ((ComposeWindow*) w)->cancel_cb_i((Fl_Widget*) w);
857 inline void uri_insert_cb_i(Fl_Widget*);
858 static void uri_insert_cb(Fl_Widget*,
void* w)
860 ((ComposeWindow*) w)->uri_insert_cb_i((Fl_Widget*) w);
863 int searchHeaderField(
const char*,
int*,
int*);
864 const char* extractHeaderField(
const char*);
865 int replaceHeaderField(
const char*,
const char*);
866 void deleteHeaderField(
const char*);
867 int checkArticleBody(
const char*);
869 Fl_Text_Editor* compEditor;
870 ComposeWindow(
const char*,
const char*,
const char*,
const char*,
872 ~ComposeWindow(
void);
876 class MainWindow :
public UI_WINDOW_CLASS
901 EVENT_SUBSCRIBE_EXIT,
904 EVENT_GL_PROPOSAL_EXIT,
907 EVENT_GL_REFRESH_EXIT,
913 EVENT_AT_REFRESH_EXIT,
933 EVENT_MOTD_VIEW_EXIT,
936 EVENT_SCROLL_NEXT_EXIT,
947 Fl_Progress* progressBar;
948 std::ostringstream aboutString;
949 ComposeWindow* composeWindow;
950 int composeWindowLock;
951 unsigned int hyperlinkStyle;
952 int hyperlinkPosition;
957 mainWindowState mainState;
958 SubscribeWindow* subscribeWindow;
959 Fl_Tile* contentGroup;
960 Fl_Tile* contentGroup2;
961 #if CFG_COCOA_SYS_MENUBAR
962 Fl_Sys_Menu_Bar* menu;
963 #else // CFG_COCOA_SYS_MENUBAR
965 #endif // CFG_COCOA_SYS_MENUBAR
966 std::size_t groupcount;
968 Fl_Hold_Browser* groupList;
971 My_Tree* articleTree;
974 My_Text_Display* text;
976 Fl_Text_Display::Style_Table_Entry* styles;
978 Fl_Text_Buffer* currentStyle;
979 Fl_Text_Buffer* currentArticle;
981 const char* currentSearchString;
982 int currentSearchPosition;
986 int groupSelect_cb_state;
987 int groupRefresh_cb_state;
988 float progress_percent_value;
989 char progress_percent_label[5];
990 bool progress_skip_update;
991 MIMEContent* mimeData;
1000 std::size_t group_num;
1001 std::size_t group_list_index;
1006 inline void progress_release_cb_i(
void)
1008 progress_skip_update =
false;
1010 static void progress_release_cb(
void* w)
1012 ((MainWindow*) w)->progress_release_cb_i();
1016 inline void exit_cb_i(
void);
1017 static void exit_cb(Fl_Widget*,
void* w)
1019 ((MainWindow*) w)->exit_cb_i();
1023 inline void print_cb_i(
void);
1024 static void print_cb(Fl_Widget*,
void* w)
1026 ((MainWindow*) w)->print_cb_i();
1030 inline void asave_cb_i(
void);
1031 static void asave_cb(Fl_Widget*,
void* w)
1033 ((MainWindow*) w)->asave_cb_i();
1037 inline void server_cb_i(
void)
1039 updateServer(UI_CB_START);
1041 static void server_cb(Fl_Widget*,
void* w)
1043 ((MainWindow*) w)->server_cb_i();
1047 inline void config_cb_i(
void);
1048 static void config_cb(Fl_Widget*,
void* w)
1050 ((MainWindow*) w)->config_cb_i();
1054 inline void identity_cb_i(
void);
1055 static void identity_cb(Fl_Widget*,
void* w)
1057 ((MainWindow*) w)->identity_cb_i();
1061 inline void about_cb_i(
void);
1062 static void about_cb(Fl_Widget*,
void* w)
1064 ((MainWindow*) w)->about_cb_i();
1068 inline void viewmotd_cb_i(
void)
1070 viewMotd(UI_CB_START);
1072 static void viewmotd_cb(Fl_Widget*,
void* w)
1074 ((MainWindow*) w)->viewmotd_cb_i();
1078 inline void mid_search_cb_i(
void);
1079 static void mid_search_cb(Fl_Widget*,
void* w)
1081 ((MainWindow*) w)->mid_search_cb_i();
1085 inline void bug_cb_i(
void);
1086 static void bug_cb(Fl_Widget*,
void* w)
1088 ((MainWindow*) w)->bug_cb_i();
1092 inline void license_cb_i(
void);
1093 static void license_cb(Fl_Widget*,
void* w)
1095 ((MainWindow*) w)->license_cb_i();
1099 inline void console_cb_i(
void);
1100 static void console_cb(Fl_Widget*,
void* w)
1102 ((MainWindow*) w)->console_cb_i();
1106 inline void gsubscribe_cb_i(
void)
1108 groupSubscribe(UI_CB_START);
1110 static void gsubscribe_cb(Fl_Widget*,
void* w)
1112 ((MainWindow*) w)->gsubscribe_cb_i();
1116 inline void gunsubscribe_cb_i(
void)
1118 std::size_t index = (std::size_t) groupList->value();
1122 fl_message_title(S(
"Warning"));
1123 rv = fl_choice(
"%s", S(
"No"),
1125 S(
"Really unsubscribe group?"));
1130 SC(
"Do not use non-ASCII for the translation of this item")
1131 fl_message_title(S("Error"));
1132 fl_alert("%s", S("No group selected"));
1140 fl_message_title(S(
"Error"));
1141 fl_alert(
"%s", S(
"Unsubscribe operation failed"));
1146 fl_message_title(S(
"Error"));
1147 fl_alert(
"%s", S(
"Exporting group states failed"));
1150 groupListRefresh(UI_CB_START);
1153 static void gunsubscribe_cb(Fl_Widget*,
void* w)
1155 ((MainWindow*) w)->gunsubscribe_cb_i();
1159 inline void grefresh_cb_i(
void)
1161 groupListRefresh(UI_CB_START);
1163 static void grefresh_cb(Fl_Widget*,
void* w)
1165 ((MainWindow*) w)->grefresh_cb_i();
1169 inline void gsort_cb_i(
void)
1174 fl_message_title(S(
"Warning"));
1175 rv = fl_choice(
"%s", S(
"No"),
1177 S(
"Really sort group list?"));
1185 groupListRefresh(UI_CB_START);
1188 static void gsort_cb(Fl_Widget*,
void* w)
1190 ((MainWindow*) w)->gsort_cb_i();
1194 inline void gselect_cb_i(
void)
1196 groupSelect(UI_CB_START, groupList->value());
1198 static void gselect_cb(Fl_Widget*,
void* w)
1200 ((MainWindow*) w)->gselect_cb_i();
1204 inline void nug_cb_i(
void)
1207 int groups = groupList->size();
1208 int current = groupList->value();
1212 for(current ? i = current - 1 : i = 0; i < groups; ++i)
1214 ur = groupGetUnreadNo(subscribedGroups[i].lwm,
1215 subscribedGroups[i].hwm, group_list[i].info);
1218 groupList->select(++i);
1219 groupSelect(UI_CB_START, i);
1225 groups = current - 1;
1230 static void nug_cb(Fl_Widget*,
void* w)
1232 ((MainWindow*) w)->nug_cb_i();
1237 inline void thrv_cb_i(
void)
1239 Fl_Menu_Item* mi = (Fl_Menu_Item*) menu->find_item(uthrv_sort_cb);
1244 if(NULL != mi) { mi->activate(); }
1249 if(NULL != mi) { mi->deactivate(); }
1251 if(NULL != currentGroup) { updateTree(); }
1252 #if CFG_COCOA_SYS_MENUBAR
1254 #endif // CFG_COCOA_SYS_MENUBAR
1256 static void thrv_cb(Fl_Widget*,
void* w)
1258 ((MainWindow*) w)->thrv_cb_i();
1263 inline void uthrv_sort_cb_i(
void)
1267 if(NULL != currentGroup) { updateTree(); }
1269 static void uthrv_sort_cb(Fl_Widget*,
void* w)
1271 ((MainWindow*) w)->uthrv_sort_cb_i();
1275 inline void onlyur_cb_i(
void)
1279 if(NULL != currentGroup) { updateTree(); }
1281 static void onlyur_cb(Fl_Widget*,
void* w)
1283 ((MainWindow*) w)->onlyur_cb_i();
1287 inline void wrap_cb_i(
void)
1289 if(Fl_Text_Display::WRAP_AT_BOUNDS != wrapMode)
1291 wrapMode = Fl_Text_Display::WRAP_AT_BOUNDS;
1293 else { wrapMode = Fl_Text_Display::WRAP_NONE; }
1294 text->wrap_mode(wrapMode, 0);
1296 static void wrap_cb(Fl_Widget*,
void* w)
1298 ((MainWindow*) w)->wrap_cb_i();
1302 inline void rot13_cb_i(
void);
1303 static void rot13_cb(Fl_Widget*,
void* w)
1305 ((MainWindow*) w)->rot13_cb_i();
1310 inline void msau_cb_i(
void);
1311 static void msau_cb(Fl_Widget*,
void* w)
1313 ((MainWindow*) w)->msau_cb_i();
1317 inline void mssar(Fl_Tree_Item*);
1318 inline void mssar_cb_i(
void);
1319 static void mssar_cb(Fl_Widget*,
void* w)
1321 ((MainWindow*) w)->mssar_cb_i();
1325 inline void maar_cb_i(
void);
1326 static void maar_cb(Fl_Widget*,
void* w)
1328 ((MainWindow*) w)->maar_cb_i();
1332 inline void magar_cb_i(
void);
1333 static void magar_cb(Fl_Widget*,
void* w)
1335 ((MainWindow*) w)->magar_cb_i();
1339 inline void aselect_cb_i(
void);
1340 static void aselect_cb(Fl_Widget*,
void* w)
1342 ((MainWindow*) w)->aselect_cb_i();
1346 inline void viewsrc_cb_i(
void)
1348 viewSrc(UI_CB_START);
1350 static void viewsrc_cb(Fl_Widget*,
void* w)
1352 ((MainWindow*) w)->viewsrc_cb_i();
1356 inline void compose_cb_i(
void)
1358 articleCompose(
false,
false);
1360 static void compose_cb(Fl_Widget*,
void* w)
1362 ((MainWindow*) w)->compose_cb_i();
1366 inline void reply_cb_i(
void)
1368 articleCompose(
true,
false);
1370 static void reply_cb(Fl_Widget*,
void* w)
1372 ((MainWindow*) w)->reply_cb_i();
1376 inline void cancel_cb_i(
void)
1378 articleCompose(
false,
true);
1380 static void cancel_cb(Fl_Widget*,
void* w)
1382 ((MainWindow*) w)->cancel_cb_i();
1386 inline void supersede_cb_i(
void)
1388 articleCompose(
true,
true);
1390 static void supersede_cb(Fl_Widget*,
void* w)
1392 ((MainWindow*) w)->supersede_cb_i();
1396 inline void email_cb_i(
void)
1400 static void email_cb(Fl_Widget*,
void* w)
1402 ((MainWindow*) w)->email_cb_i();
1406 inline void nua_cb_i(
void)
1408 std::size_t index = (std::size_t) groupList->value();
1412 SC(
"Do not use non-ASCII for the translation of this item")
1413 fl_message_title(S("Error"));
1414 fl_alert("%s", S("No group selected"));
1416 else { ascrolldown_cb(
false); }
1418 static void nua_cb(Fl_Widget*,
void* w)
1420 ((MainWindow*) w)->nua_cb_i();
1424 inline void pra_cb_i(
void)
1429 if(NULL == lastArticleHE)
1431 SC(
"Do not use non-ASCII for the translation of this item")
1432 fl_message_title(S("Error"));
1433 fl_alert("%s", S("No previously read article stored for group"));
1438 len = std::strlen(mid);
1440 if(NULL == searchSelectArticle(&mid[1], len - (std::size_t) 2))
1442 SC(
"Do not use non-ASCII for the translation of this item")
1443 fl_message_title(S("Error"));
1444 fl_alert("%s", "Previous article not found (bug)");
1448 static
void pra_cb(Fl_Widget*,
void* w)
1450 ((MainWindow*) w)->pra_cb_i();
1454 inline void hyperlink_cb_i(
void)
1456 hyperlinkHandler(hyperlinkPosition);
1458 static void hyperlink_cb(Fl_Widget*,
void* w)
1460 ((MainWindow*) w)->hyperlink_cb_i();
1463 void clearTree(
void);
1464 void scrollTree(ui_scroll, Fl_Tree_Item*);
1465 bool checkTreeBranchForUnread(Fl_Tree_Item*);
1466 bool checkTreeBranchForItem(Fl_Tree_Item*, Fl_Tree_Item*);
1468 void updateTree(
void);
1469 inline void collapseTree(
void)
1473 for(i = 0; i < articleTree->root()->children(); ++i)
1475 articleTree->root()->child(i)->close();
1478 void groupSubscribe(
int);
1481 void groupListUpdateEntry(std::size_t);
1482 int groupStateMerge(
void);
1483 void groupSelect(
int,
int);
1485 void groupListGetProposal(
int);
1486 void updateArticleTree(
int);
1487 void articleSelect(
int);
1490 void stripAngleAddress(
char*);
1491 void articleCompose(
bool,
bool);
1492 void sendEmail(
void);
1493 Fl_Tree_Item* searchSelectArticle(
const char*, std::size_t);
1494 void storeMIMEEntityToFile(
const char*,
const char*);
1495 void hyperlinkHandler(
int);
1497 bool stateMachine(
enum mainWindowEvent);
1499 void viewArticle(
int,
const char*);
1500 static void group_list_refresh_timer_cb(
void* w)
1502 ((MainWindow*) w)->groupListRefresh(UI_CB_START);
1508 Fl::add_timeout(iv, group_list_refresh_timer_cb, (
void*) w);
1511 static void serverconf_cb(
void* w)
1513 ((MainWindow*) w)->updateServer(UI_CB_CONTINUE);
1515 static void subscribe_cb1(
void* w)
1517 ((MainWindow*) w)->groupSubscribe(UI_CB_CONTINUE);
1519 static void subscribe_cb2(
void* w)
1521 ((MainWindow*) w)->groupSubscribe(UI_CB_FINISH);
1523 static void groupproposal_cb(
void* w)
1525 ((MainWindow*) w)->groupListGetProposal(UI_CB_CONTINUE);
1527 static void refresh_cb1(
void* w)
1529 ((MainWindow*) w)->groupListRefresh(UI_CB_CONTINUE);
1531 static void refresh_cb2(
void* w)
1533 ((MainWindow*) w)->groupListRefresh(UI_CB_FINISH);
1535 static void group_cb(
void* w)
1537 ((MainWindow*) w)->groupSelect(UI_CB_CONTINUE, 0);
1539 static void overview_cb(
void* w)
1541 ((MainWindow*) w)->updateArticleTree(UI_CB_FINISH);
1543 static void header_cb(
void* w)
1545 ((MainWindow*) w)->updateArticleTree(UI_CB_CONTINUE);
1547 static void body_cb(
void* w)
1549 ((MainWindow*) w)->articleSelect(UI_CB_CONTINUE);
1551 static void motd_cb(
void* w)
1553 ((MainWindow*) w)->viewMotd(UI_CB_CONTINUE);
1555 static void article_cb(
void* w)
1557 ((MainWindow*) w)->viewArticle(UI_CB_CONTINUE, NULL);
1559 static void src_cb(
void* w)
1561 ((MainWindow*) w)->viewSrc(UI_CB_CONTINUE);
1563 static void post_cb(
void* w)
1565 ((MainWindow*) w)->articlePost(UI_CB_CONTINUE, NULL);
1568 inline void asearch_cb_i(
void);
1569 static void asearch_cb(Fl_Widget*,
void* w)
1571 ((MainWindow*) w)->asearch_cb_i();
1573 void ascrolldown_cb(
bool);
1574 void articlePost(
int,
const char*);
1575 inline void composeComplete(
void)
1577 if(!stateMachine(EVENT_COMPOSE_EXIT))
1579 PRINT_ERROR(
"Error in main window state machine");
1582 void calculatePercent(std::size_t, std::size_t);
1583 inline int groupStateExport(
void)
1587 void updateServer(
int);
1588 void groupListRefresh(
int);
1589 inline void groupListImport(
void)
1592 groupListRefresh(UI_CB_START);
1594 void articleUpdate(Fl_Text_Buffer*);
1595 inline int getTilingX(
void) {
return(groupList->w()); }
1596 inline int getTilingY(
void) {
return(articleTree->h()); }
1597 inline void setTilingX(
int tx)
1600 if(50 > tx) { tx = 50; }
1601 if(w() - 50 < tx) { tx = w() - 50; }
1603 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1606 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1608 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1611 inline void setTilingY(
int ty)
1614 if(50 > ty) { ty = 50; }
1615 if(groupList->h() - 50 < ty) { ty = groupList->h() - 50; }
1617 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1620 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1622 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1623 (1, contentGroup2->y() + 140,
1624 1, contentGroup2->y() + ty);
1626 MainWindow(
const char*);
1635 #define UI_STATUS(s) { if(mainWindow) { mainWindow->statusBar->label(s); } }
1638 #define UI_READY() \
1642 mainWindow->progressBar->value(0.0); \
1643 mainWindow->progressBar->label(""); \
1644 mainWindow->default_cursor(FL_CURSOR_DEFAULT); \
1645 mainWindow->busy = false; \
1654 mainWindow->progressBar->value(0.0); \
1655 SC("This string must fit into the progress bar box") \
1656 mainWindow->progressBar->label(S("Busy")); \
1657 mainWindow->default_cursor(FL_CURSOR_WAIT); \
1658 mainWindow->busy = true; \
1663 #define UI_PROGRESS(s, e) \
1667 mainWindow->calculatePercent(s, e); \
1668 if(100.0 == progress_percent_value || !progress_skip_update) \
1670 mainWindow->progressBar->value(progress_percent_value); \
1671 mainWindow->progressBar->copy_label(progress_percent_label); \
1673 if(!mainWindow->busy) \
1675 mainWindow->default_cursor(FL_CURSOR_WAIT); \
1676 mainWindow->busy = true; \
1679 progress_skip_update = true; \
1680 Fl::add_timeout(0.1, progress_release_cb, this); \
1691 #include "pixmaps/pixmaps.c"
1694 static Fl_Pixmap pm_window_icon(xpm_window_icon);
1695 #endif // USE_WINDOW_ICON
1696 static Fl_Pixmap pm_own(xpm_own);
1697 static Fl_Pixmap pm_reply_to_own(xpm_reply_to_own);
1698 static Fl_Pixmap pm_score_down(xpm_score_down);
1699 static Fl_Pixmap pm_score_up(xpm_score_up);
1701 static Fl_Text_Buffer* dummyTb;
1703 static Fl_RGB_Image mainIcon(&pm_window_icon);
1704 #endif // USE_WINDOW_ICON
1705 static MainWindow* mainWindow = NULL;
1706 static ProtocolConsole* protocolConsole = NULL;
1707 static int exitRequest = 0;
1708 static bool lockingInitialized =
false;
1709 static int offset_correction_x;
1710 static int offset_correction_y;
1718 static void gui_set_default_font(
void)
1720 fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
1727 static const char* gui_greeting(
void)
1729 std::ostringstream greetingString;
1735 if(!std::strcmp(CFG_NAME,
"flnews"))
1741 <<
" __/ /_ / / _______ _______ ___ ___ _______\n"
1742 <<
" /_ __/ / / / ___ \\ / ___ \\ / / / / / _____\\\n"
1743 <<
" / / / / / / / / / /__/__/ / /_/|_/ / /__/_____\n"
1744 <<
" / / / / / / / / / /_____ / ___ / ______/ /\n"
1745 <<
"/__/ /__/ /__/ /__/ \\_______/ \\__/ /___/ \\_______/";
1747 else { greetingString << CFG_NAME; }
1748 greetingString <<
"\n\n"
1749 << S(
"A fast and lightweight Usenet newsreader for Unix.") <<
"\n\n"
1752 << S(
"is based in part on the work of the following projects:") <<
"\n"
1753 <<
"- FLTK project (http://www.fltk.org/)" <<
"\n"
1754 <<
"- The Unicode\xC2\xAE Standard (http://www.unicode.org/)" <<
"\n"
1755 <<
" Unicode is a registered trademark of Unicode, Inc. in the" <<
"\n"
1756 <<
" United States and other countries" <<
"\n"
1758 # if CFG_USE_LIBRESSL
1759 <<
"- LibreSSL project (http://www.libressl.org/)" <<
"\n"
1760 # else // CFG_USE_LIBRESSL
1761 <<
"- OpenSSL project (https://www.openssl.org/)" <<
"\n"
1762 # endif // CFG_USE_LIBRESSL
1763 <<
" This product includes software developed by" <<
"\n"
1764 <<
" the OpenSSL Project for use in the OpenSSL Toolkit" <<
"\n"
1765 <<
" This product includes software written by" <<
"\n"
1766 <<
" Tim Hudson <tjh@cryptsoft.com>" <<
"\n"
1767 <<
" This product includes cryptographic software written by" <<
"\n"
1768 <<
" Eric Young <eay@cryptsoft.com>" <<
"\n"
1769 #endif // CFG_USE_TLS
1771 <<
"- zlib compression library (http://zlib.net/)" <<
"\n"
1772 #endif // CFG_USE_ZLIB
1777 const std::string& gs = greetingString.str();
1781 len = std::strlen(s1) + (std::size_t) 1;
1783 std::memcpy(s2, s1, len);
1793 #if CFG_USE_XSI && !CFG_NLS_DISABLE
1794 static const char* gui_utf8_iso(
const char* s)
1796 const char* res = NULL;
1801 if(!fl_utf8locale())
1805 len = fl_utf8toa(s, (
unsigned int) std::strlen(s), NULL, 0);
1806 tmp =
new char[len + 1U];
1807 if(fl_utf8toa(s, (
unsigned int) std::strlen(s), tmp, len + 1U) != len)
1811 else { res = (
const char*) tmp; }
1816 len = (
unsigned int) std::strlen(s);
1817 tmp =
new char[len + 1U];
1818 std::strncpy(tmp, s, len + 1U);
1819 res = (
const char*) tmp;
1824 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
1833 static int gui_save_to_file(
const char* pathname, Fl_Text_Buffer* tbuf)
1836 char* s = tbuf->text();
1841 std::free((
void*) s);
1859 static void gui_check_article(Fl_Text_Buffer* tbuf)
1863 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1865 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1868 int len = tbuf->length();
1878 eol = tbuf->line_end(pos);
1879 if (1000 < eol - pos)
1887 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1893 tbuf->append(
"[Error]\n");
1894 tbuf->append(S(
"Invalid line length"));
1909 static void gui_process_shy(Fl_Text_Buffer* tbuf)
1916 rv = tbuf->findchar_forward(pos_shy, 0x00ADU, &pos_shy);
1920 rv2 = tbuf->next_char(pos_shy);
1921 if(0x000AU == tbuf->char_at(rv2))
1924 tbuf->replace(pos_shy, rv2,
"-");
1926 else { tbuf->remove(pos_shy, rv2); }
1937 static const char* gui_check_re_prefix(
const char* subject)
1939 bool prefix_replaced;
1941 if((std::size_t) 3 <= std::strlen(subject))
1947 prefix_replaced =
false;
1948 if( (!std::strncmp(subject,
"Re:", 3) &&
' ' != subject[3])
1949 || !std::strncmp(subject,
"RE:", 3)
1950 || !std::strncmp(subject,
"re:", 3)
1951 || !std::strncmp(subject,
"AW:", 3)
1952 || !std::strncmp(subject,
"Aw:", 3) )
1955 " replaced with \"Re: \"");
1956 subject = &subject[3];
1957 if(
' ' == subject[0]) { subject = &subject[1]; }
1958 prefix_replaced =
true;
1961 while(prefix_replaced);
1963 if(!std::strncmp(subject,
"Re: ", 4)) { subject = &subject[4]; }
1975 static const char* gui_create_newsgroup_list(
const char** array)
1977 static const char error[] =
"[Error]";
1979 std::size_t size_max = (std::size_t) -1;
1981 std::size_t len = 0;
1985 while(NULL != array[i])
1987 if(UINT_MAX == i) {
break; }
1988 j = std::strlen(array[i]);
1989 if(size_max - len < j) {
break; }
1993 if(!i || (size_max - len < i))
1995 res =
new char[std::strlen(error) + (size_t) 1];
1996 std::strcat(res, error);
2003 res =
new char[len];
2005 for(j = 0; i > j; ++j)
2007 if(j) { std::strcat(res,
","); }
2008 std::strcat(res, array[j]);
2010 res[len - (std::size_t) 1] = 0;
2020 static int gui_last_sig_separator(
char* buf)
2027 p = std::strstr(buf,
"\n-- \n");
2033 q = std::strstr(buf,
"\n________________________________________"
2034 "_______________________________________|\n");
2035 if(NULL != q && p > q) { res = 1; }
2047 static void gui_cite_content(Fl_Text_Buffer* compText,
const char* ca,
2050 const char* ngl = gui_create_newsgroup_list(nga);
2063 case 0: { qm =
">";
break; }
2064 case 1: { qm =
"> ";
break; }
2067 PRINT_ERROR(
"Quoting style configuration not supported");
2074 if(compText->length())
2076 while(compText->char_at(pos))
2079 if((
unsigned int)
'>' == compText->char_at(pos))
2084 compText->insert(pos, qm);
2092 c = compText->char_at(pos);
2093 next = compText->char_at(compText->next_char(pos));
2094 if((
unsigned int)
'>' == c)
2096 if((
unsigned int)
' ' == next)
2099 compText->remove(pos + 1, pos + 2);
2102 pos = compText->next_char(pos);
2103 next = compText->char_at(pos);
2105 while((
unsigned int)
'>' == next || (
unsigned int)
' ' == next);
2111 c = compText->char_at(pos);
2112 next = compText->char_at(compText->next_char(pos));
2113 if((
unsigned int)
'>' == c)
2115 if((
unsigned int)
'>' == next)
2118 compText->insert(++pos,
" ");
2120 else if((
unsigned int)
'>' != next
2121 && (
unsigned int)
' ' != next)
2124 compText->insert(++pos,
" ");
2127 pos = compText->next_char(pos);
2129 while((
unsigned int)
'>' == next || (
unsigned int)
' ' == next);
2133 rv = compText->findchar_forward(pos, (
unsigned int)
'\n',
2135 if(!rv) {
break; }
else { pos = ++pos_found; }
2142 compText->insert(0,
"\n"); compText->insert(0, qm);
2146 if(NULL == intro) { compText->insert(0,
"[Error] wrote:\n"); }
2149 compText->insert(0,
"\n");
2150 compText->insert(0, intro);
2155 compText->append(
"\n");
2165 #define UI_HDR_FIELDS (std::size_t) 14
2166 #define UI_HDR_PAD(s, n) { for(i = 0; i < n; ++i) { s << " "; } }
2169 static const char* f[UI_HDR_FIELDS] =
2182 S(
"Transfer-Encoding"),
2186 std::size_t flen[UI_HDR_FIELDS];
2187 std::size_t fpad[UI_HDR_FIELDS];
2188 std::ostringstream hdrData;
2194 std::size_t largest = 0;
2197 for(i = 0; i < UI_HDR_FIELDS; ++i)
2199 len = std::strlen(f[i]);
2200 #if CFG_USE_XSI && !CFG_NLS_DISABLE
2204 if(INT_MAX < len) { len = INT_MAX; }
2205 rv = fl_utf_nb_char((
const unsigned char*) f[i], (
int) len);
2206 if(0 > rv) { flen[i] = len; }
2207 else { flen[i] = (std::size_t) rv; }
2208 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
2211 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
2213 for(i = 0; i < UI_HDR_FIELDS; ++i)
2215 if(largest < flen[i]) { largest = flen[i]; }
2217 for(i = 0; i < UI_HDR_FIELDS; ++i) { fpad[i] = largest - flen[i]; }
2220 UI_HDR_PAD(hdrData, fpad[0]);
2221 hdrData << f[0] <<
": " << h->
subject <<
"\n";
2225 UI_HDR_PAD(hdrData, fpad[1]);
2226 hdrData << f[1] <<
": " << date <<
"\n";
2228 UI_HDR_PAD(hdrData, fpad[2]);
2229 hdrData << f[2] <<
": " << h->
from <<
"\n";
2234 UI_HDR_PAD(hdrData, fpad[3]);
2235 hdrData << f[3] <<
": " << h->
reply2 <<
"\n";
2238 UI_HDR_PAD(hdrData, fpad[4]);
2239 hdrData << f[4] <<
": ";
2241 while(NULL != h->
groups[i])
2243 if(i) { hdrData <<
","; }
2244 hdrData << h->
groups[i++];
2249 UI_HDR_PAD(hdrData, fpad[5]);
2250 hdrData << f[5] <<
": " << h->
fup2 <<
"\n";
2255 UI_HDR_PAD(hdrData, fpad[6]);
2256 hdrData << f[6] <<
": " << h->
dist <<
"\n";
2259 UI_HDR_PAD(hdrData, fpad[7]);
2260 hdrData << f[7] <<
": " << h->
msgid <<
"\n";
2263 UI_HDR_PAD(hdrData, fpad[8]);
2264 hdrData << f[8] <<
": " << h->
supers <<
"\n";
2268 UI_HDR_PAD(hdrData, fpad[9]);
2269 hdrData << f[9] <<
": " << h->
org <<
"\n";
2273 UI_HDR_PAD(hdrData, fpad[10]);
2274 hdrData << f[10] <<
": " << h->
uagent <<
"\n";
2278 UI_HDR_PAD(hdrData, fpad[10]);
2279 hdrData << f[10] <<
": " << h->
x_newsr <<
"\n";
2283 UI_HDR_PAD(hdrData, fpad[10]);
2284 hdrData << f[10] <<
": " << h->
x_pagent <<
"\n";
2288 UI_HDR_PAD(hdrData, fpad[10]);
2289 hdrData << f[10] <<
": " << h->
x_mailer <<
"\n";
2293 UI_HDR_PAD(hdrData, fpad[11]);
2294 hdrData << f[11] <<
": " << h->
mime_cte <<
"\n";
2298 UI_HDR_PAD(hdrData, fpad[12]);
2299 hdrData << f[12] <<
": " << h->
mime_ct <<
"\n";
2303 UI_HDR_PAD(hdrData, fpad[13]);
2306 hdrData << f[13] <<
":" <<
"\x1D";
2308 while(NULL != h->
refs[i]) { hdrData <<
"[" << i++ <<
"]"; }
2311 hdrData << std::flush;
2322 const std::string& hs = hdrData.str();
2324 len = std::strlen(hs.c_str());
2325 s =
new char[++len];
2326 std::strncpy(s, hs.c_str(), len);
2343 static const char* gui_create_link_to_entity(
const char* msgid,
2346 const char* link = NULL;
2348 const char* confdir = NULL;
2351 std::ostringstream entity_no;
2356 tb.text(
"<file://");
2358 tb.append(
"/.mime/entities/");
2360 len = std::strlen(msgid);
2361 msgid_buf =
new char[len];
2362 std::strncpy(msgid_buf, &msgid[1], --len);
2363 msgid_buf[--len] = 0;
2364 tb.append(msgid_buf);
2369 entity_no.str(std::string());
2370 entity_no << entity << std::flush;
2371 const std::string& s = entity_no.str();
2372 tb.append(s.c_str());
2390 static void gui_decode_mime_entities(Fl_Text_Buffer *tb,
2391 MIMEContent* mimeData,
2394 const char* p = NULL;
2395 const char* q = NULL;
2406 if(NULL == mimeData)
2408 tb->append(S(
"MIME content handling error"));
2413 num = mimeData->parts();
2415 for(i = first; i < num; ++i)
2417 body = mimeData->part(i, &cte, &ct);
2422 last_char = tb->byte_at(tb->length() - 1);
2423 if((
char) 0x0A != last_char) { tb->append(
"\n"); }
2427 if(mimeData->is_multipart())
2429 header = mimeData->part_header(i);
2438 if(ENC_CD_ATTACHMENT == mimeData->type(i)) { attachment = 1; }
2442 tb->append(S(
"Declared as attachment by sender"));
2445 p = gui_create_link_to_entity(msgid, i);
2446 if(NULL == p) { tb->append(
"[Error]"); }
2447 else { tb->append(p); }
2448 std::free((
void*) p);
2456 tb->append(S(
"MIME content type not supported"));
2459 p = gui_create_link_to_entity(msgid, i);
2460 if(NULL == p) { tb->append(
"[Error]"); }
2461 else { tb->append(p); }
2462 std::free((
void*) p);
2470 tb->append(S(
"MIME content decoding failed"));
2475 if(ct->
flags & ENC_CT_FLAG_FLOWED)
2478 ct->
flags & ENC_CT_FLAG_DELSP,
2479 ct->
flags & ENC_CT_FLAG_INSLINE);
2487 if(p != q && p != body) {
enc_free((
void*) p); }
2497 S(
"Conversion from canonical to local form failed"));
2502 if(p != q && p != body) {
enc_free((
void*) p); }
2506 if(p != body) {
enc_free((
void*) p); }
2518 static int gui_check_pathname(
const char* pathname)
2527 fl_message_title(S(
"Warning"));
2528 rv = !fl_choice(
"%s", S(
"Cancel"),
2530 S(
"File exists\nReally continue?"));
2545 static int gui_populate_group_list(
const char* grouplist)
2554 if(NULL != grouplist)
2556 len = std::strlen(grouplist);
2559 buf =
new char[len + (std::size_t) 1];
2562 rv = std::sscanf(&grouplist[pos],
"%s%n", buf, &pos_new);
2563 if (1 != rv || !pos_new) {
break; }
2582 int My_Text_Display::handle(
int event)
2595 if(Fl::event_key() == 0x20)
2598 mainWindow->ascrolldown_cb(
true);
2602 else if(!std::strcmp(Fl::event_text(),
"/"))
2604 mainWindow->asearch_cb_i();
2612 if(NULL != mStyleBuffer)
2616 pos = xy_to_position(x, y);
2617 style = mStyleBuffer->char_at(pos);
2618 if(NULL != mainWindow)
2620 if(style == mainWindow->hyperlinkStyle)
2623 fl_cursor(FL_CURSOR_HAND);
2625 else { fl_cursor(FL_CURSOR_DEFAULT); }
2635 if(NULL != mStyleBuffer)
2637 button = Fl::event_button();
2638 if(FL_LEFT_MOUSE == button)
2643 pos = xy_to_position(x, y);
2644 style = mStyleBuffer->char_at(pos);
2646 if(NULL != mainWindow)
2648 if(style == mainWindow->hyperlinkStyle)
2650 if(FL_PUSH == event) { linkPushed = pos; }
2651 else if(pos == linkPushed)
2656 mainWindow->hyperlinkPosition = pos;
2664 if(FL_RELEASE == event) { linkPushed = -1; }
2674 if(!res) { res = Fl_Text_Display::handle(event); }
2686 int My_Tree::handle(
int event)
2691 if(update_in_progress())
2701 #ifdef FL_ABI_VERSION
2702 # if 10303 <= FL_ABI_VERSION
2704 if(Fl::event_key() == FL_Down)
2706 Fl_Tree_Item* ti = get_item_focus();
2707 if(NULL != ti && NULL == next_visible_item(ti, FL_Down))
2714 # endif // 10303 <= FL_ABI_VERSION
2715 #endif // FL_ABI_VERSION
2717 if(Fl::event_key() == FL_Enter)
2719 #ifdef FL_ABI_VERSION
2720 # if 10301 <= FL_ABI_VERSION
2723 Fl_Tree_Item* ti = first_selected_item();
2724 if(NULL != ti) { deselect(ti); }
2725 select(get_item_focus(), 1);
2726 # endif // 10301 <= FL_ABI_VERSION
2727 #endif // FL_ABI_VERSION
2732 else if(Fl::event_key() == 0x20)
2734 mainWindow->ascrolldown_cb(
true);
2739 else if(!std::strcmp(Fl::event_text(),
"/"))
2741 mainWindow->asearch_cb_i();
2749 res = Fl_Tree::handle(event);
2774 bool MainWindow::stateMachine(
enum mainWindowEvent operation)
2784 case EVENT_SUBSCRIBE:
2785 case EVENT_GL_REFRESH:
2789 case EVENT_SRC_VIEW:
2790 case EVENT_MOTD_VIEW:
2792 mainState = STATE_MUTEX;
2797 mainState = STATE_SERVER1;
2800 case EVENT_G_SELECT:
2802 mainState = STATE_GROUP;
2805 case EVENT_A_PREPARE:
2807 mainState = STATE_NEXT;
2810 case EVENT_SCROLL_NEXT:
2812 mainState = STATE_SCROLL;
2817 mainState = STATE_COMPOSE;
2820 case EVENT_SERVER_EXIT:
2821 case EVENT_G_SELECT_EXIT:
2822 case EVENT_GL_REFRESH_EXIT:
2823 case EVENT_SCROLL_NEXT_EXIT:
2841 case EVENT_SUBSCRIBE_EXIT:
2842 case EVENT_GL_REFRESH_EXIT:
2843 case EVENT_A_VIEW_EXIT:
2844 case EVENT_A_MAAR_EXIT:
2845 case EVENT_A_MAGAR_EXIT:
2846 case EVENT_SRC_VIEW_EXIT:
2847 case EVENT_MOTD_VIEW_EXIT:
2849 mainState = STATE_READY;
2865 case EVENT_GL_PROPOSAL:
2867 mainState = STATE_PROPOSAL;
2870 case EVENT_GL_REFRESH:
2872 mainState = STATE_SERVER2;
2875 case EVENT_SERVER_EXIT:
2877 mainState = STATE_READY;
2893 case EVENT_SERVER_EXIT:
2894 case EVENT_GL_PROPOSAL_EXIT:
2899 case EVENT_GL_REFRESH_EXIT:
2901 mainState = STATE_READY;
2913 case STATE_PROPOSAL:
2917 case EVENT_SERVER_EXIT:
2922 case EVENT_GL_PROPOSAL_EXIT:
2924 mainState = STATE_READY;
2927 case EVENT_GL_REFRESH:
2929 mainState = STATE_SERVER2;
2945 case EVENT_G_SELECT_EXIT:
2946 case EVENT_AT_REFRESH:
2951 case EVENT_AT_REFRESH_EXIT:
2953 mainState = STATE_READY;
2969 case EVENT_A_PREPARE:
2971 mainState = STATE_NEXT;
2974 case EVENT_SCROLL_NEXT_EXIT:
2976 mainState = STATE_READY;
2992 case EVENT_A_SELECT:
2993 case EVENT_SCROLL_NEXT_EXIT:
2998 case EVENT_A_SELECT_EXIT:
3000 mainState = STATE_READY;
3018 mainState = STATE_POST;
3021 case EVENT_COMPOSE_EXIT:
3023 mainState = STATE_READY;
3039 case EVENT_POST_EXIT:
3041 mainState = STATE_COMPOSE;
3056 PRINT_ERROR(
"Invalid state detected by main window state machine");
3057 mainState = STATE_READY;
3070 void MainWindow::exit_cb_i(
void)
3073 if(Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape)
3086 void MainWindow::print_cb_i(
void)
3088 const Fl_Font font = FL_COURIER;
3089 const Fl_Fontsize fontsize = 14;
3090 const char line[] =
"________________________________________"
3091 "________________________________________";
3092 int old_scrollbar_size = Fl::scrollbar_size();
3097 Fl_Text_Display canvas(0, 0, 100, 100);
3100 int frompage, topage;
3111 int current_line = 1;
3114 if(NULL == currentGroup)
3116 SC(
"Do not use non-ASCII for the translation of this item")
3117 fl_message_title(S("Error"));
3118 fl_alert("%s", S("No group selected"));
3120 else if(NULL == currentArticleHE)
3122 SC(
"Do not use non-ASCII for the translation of this item")
3123 fl_message_title(S("Error"));
3124 fl_alert("%s", S("No article selected"));
3129 fl_font(font, fontsize);
3130 fl_measure(line, w = 0, lh = 0);
3131 if(0 >= w || 0 >= lh) { res = -1; }
3132 else { h = (int) std::ceil((
double) w * std::sqrt(2.0)); }
3136 p = text->buffer()->text();
3137 if(NULL != p) { tb.text(p); }
3138 std::free((
void*) p);
3139 lines = tb.count_lines(0, tb.length());
3141 p = currentStyle->text();
3142 if(NULL != p) { sb.text(p); }
3143 std::free((
void*) p);
3147 canvas.box(FL_NO_BOX);
3148 canvas.textfont(font);
3149 canvas.textsize(fontsize);
3150 canvas.resize(0, 0, w, h);
3152 canvas.highlight_data(&sb, styles, styles_len,
'A', NULL, NULL);
3156 while(canvas.position_to_xy(i, &x, &y))
3158 if(!canvas.move_down()) {
break; }
3159 i = canvas.insert_position();
3165 --lpp;
if(0 >= lpp) { res = -1; }
3168 for(i = 0; i < lpp; ++i) { tb.append(
"\n"); }
3169 pages = lines / lpp;
3170 if(lines % lpp) { ++pages; }
3171 if(1 > pages) { res = -1; }
3178 res = printer.start_job(pages, &frompage, &topage);
3182 Fl::scrollbar_size(0);
3183 for(i = 1; i <= pages; ++i)
3186 canvas.scroll(current_line, 0);
3188 if(i >= frompage && i <= topage)
3191 res = printer.start_page();
3194 res = printer.printable_rect(&pw, &ph);
3197 sf = (float) pw / (
float) w;
3198 tmp = (float) ph / (
float) h;
3199 if(std::fabs(tmp) < std::fabs(sf)) { sf = tmp; }
3203 printer.print_widget((Fl_Widget*) &canvas);
3205 rv = printer.end_page();
3206 if(!res) { res = rv; }
3214 current_line += lpp;
3218 Fl::scrollbar_size(old_scrollbar_size);
3225 SC(
"Do not use non-ASCII for the translation of this item")
3226 fl_message_title(S("Error"));
3227 fl_alert("%s", S("Printing failed or aborted"));
3235 void MainWindow::asave_cb_i(
void)
3237 const char* pathname;
3240 if(NULL == currentGroup)
3242 SC(
"Do not use non-ASCII for the translation of this item")
3243 fl_message_title(S("Error"));
3244 fl_alert("%s", S("No group selected"));
3246 else if(NULL == currentArticleHE)
3248 SC(
"Do not use non-ASCII for the translation of this item")
3249 fl_message_title(S("Error"));
3250 fl_alert("%s", S("No article selected"));
3254 SC(
"Do not use characters for the translation that cannot be")
3255 SC("converted to the ISO 8859-1 character set for this item.")
3256 SC("Leave the original
string in place if in doubt.")
3257 const
char* title = S("Save article");
3260 fl_file_chooser_ok_label(S("Save"));
3261 if(NULL != suggested_pathname)
3263 pathname = fl_file_chooser(title,
"*", suggested_pathname, 0);
3264 if(NULL != pathname)
3267 rv = gui_check_pathname(pathname);
3270 rv = gui_save_to_file(pathname, currentArticle);
3273 SC(
"Do not use non-ASCII for the translation of this item")
3274 fl_message_title(S("Error"));
3275 fl_alert("%s", S("Operation failed"));
3288 void MainWindow::asearch_cb_i(
void)
3290 SearchWindow* sw = NULL;
3294 std::size_t tmp, tmp2;
3296 int start, end, len;
3297 int sel_start, sel_end;
3299 SC("Do not use characters for the translation that cannot be converted to")
3300 SC("the ISO 8859-1 character set for this item.")
3301 SC("Leave the original
string in place if in doubt.")
3302 const
char* titleString = S("Search in article");
3305 if(NULL == currentArticleHE)
3307 SC(
"Do not use non-ASCII for the translation of this item")
3308 fl_message_title(S("Error"));
3309 fl_alert("%s", S("No article selected"));
3314 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3319 title = gui_utf8_iso(titleString);
3322 sw =
new SearchWindow(title, ¤tSearchString);
3325 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3326 sw =
new SearchWindow(titleString, ¤tSearchString);
3327 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3333 sw->default_cursor(FL_CURSOR_DEFAULT);
3336 while(!sw->finished) { Fl::wait(); }
3337 sw->default_cursor(FL_CURSOR_WAIT);
3338 result = sw->finished;
3342 currentArticle->unhighlight();
3346 UI_STATUS(S(
"Search cancelled, reset start position."));
3347 currentSearchPosition = 0;
3352 UI_STATUS(S(
"Searching in article ..."));
3358 p = currentArticle->text();
3359 found = !enc_uc_search(p, (
size_t) currentSearchPosition,
3360 currentSearchString, &tmp, &tmp2);
3361 if((std::size_t) INT_MAX <= tmp) { found_pos = INT_MAX; }
3362 else { found_pos = (int) tmp; }
3363 if((std::size_t) INT_MAX <= tmp2) { len = INT_MAX; }
3364 else { len = (int) tmp2; }
3365 std::free((
void*) p);
3370 found = currentArticle->search_forward(currentSearchPosition,
3371 currentSearchString,
3374 len = (int) std::strlen(currentSearchString);
3380 if(INT_MAX - start < len) { len = INT_MAX - start; }
3382 currentSearchPosition = end;
3383 currentArticle->highlight(start, end);
3384 UI_STATUS(S(
"Search string found and marked, position stored."));
3387 if(currentArticle->highlight_position(&sel_start, &sel_end))
3390 text->insert_position(0);
3391 text->show_insert_position();
3392 text->insert_position(sel_end);
3393 text->show_insert_position();
3398 UI_STATUS(S(
"Search string not found, reset start position."));
3400 currentSearchPosition = 0;
3407 if(NULL != sw) {
delete sw; }
3416 void MainWindow::calculatePercent(std::size_t current, std::size_t complete)
3418 std::ostringstream percentString;
3420 progress_percent_value = 100.0;
3421 progress_percent_label[0] =
'1';
3422 progress_percent_label[1] =
'0';
3423 progress_percent_label[2] =
'0';
3424 progress_percent_label[3] =
'%';
3425 if(complete && (current < complete))
3427 progress_percent_value = (float) current / (
float) complete;
3428 progress_percent_value *= (float) 100.0;
3429 percentString.precision(0);
3430 percentString << std::fixed << progress_percent_value <<
"%"
3442 const std::string& ps = percentString.str();
3444 std::strncpy(progress_percent_label, ps.c_str(), (std::size_t) 4);
3447 progress_percent_label[4] = 0;
3454 void MainWindow::config_cb_i(
void)
3457 SC("Do not use characters for the translation that cannot be converted to")
3458 SC("the ISO 8859-1 character set for this item.")
3459 SC("Leave the original
string in place if in doubt.")
3460 const
char* titleString = S("Configuration");
3464 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3469 title = gui_utf8_iso(titleString);
3472 new MiscCfgWindow(title);
3475 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3476 new MiscCfgWindow(titleString);
3477 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3484 void MainWindow::identity_cb_i(
void)
3487 SC("Do not use characters for the translation that cannot be converted to")
3488 SC("the ISO 8859-1 character set for this item.")
3489 SC("Leave the original
string in place if in doubt.")
3490 const
char* titleString = S("Identity configuration");
3494 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3499 title = gui_utf8_iso(titleString);
3502 new IdentityCfgWindow(title);
3505 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3506 new IdentityCfgWindow(titleString);
3507 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3514 void MainWindow::mid_search_cb_i(
void)
3517 SC("Do not use characters for the translation that cannot be converted to")
3518 SC("the ISO 8859-1 character set for this item.")
3519 SC("Leave the original
string in place if in doubt.")
3520 const
char* titleString = S("Message-ID search");
3524 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3529 title = gui_utf8_iso(titleString);
3532 new MIDSearchWindow(title);
3535 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3536 new MIDSearchWindow(titleString);
3537 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3544 void MainWindow::about_cb_i(
void)
3546 std::ostringstream titleString;
3550 SC("Do not use characters for the translation that cannot be converted to")
3551 SC("the ISO 8859-1 character set for this item.")
3552 SC("Leave the original
string in place if in doubt.")
3553 titleString << S("About") << " " << CFG_NAME << std::flush;
3565 const std::
string& ts = titleString.str();
3566 const std::
string& as = aboutString.str();
3569 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3574 title = gui_utf8_iso(ts.c_str());
3577 fl_message_title(title);
3580 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3581 fl_message_title(ts.c_str());
3582 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3585 fl_message(
"%s", as.c_str());
3592 void MainWindow::bug_cb_i()
3594 std::ostringstream subjectString;
3595 std::ostringstream configString;
3596 std::ostringstream contentString;
3597 std::ostringstream titleString;
3604 configString <<
"Configuration:" <<
"\n"
3605 << CFG_NAME <<
" " << CFG_VERSION
3606 <<
" " <<
"for" <<
" " << CFG_OS <<
"\n"
3608 <<
"(This is a modified version!)" <<
"\n"
3609 #endif // CFG_MODIFIED
3610 <<
"Unicode version: " << UC_VERSION <<
"\n"
3612 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3613 <<
"Enabled" <<
"\n"
3614 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3615 <<
"Disabled" <<
"\n"
3616 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3617 <<
"Message locale: " <<
nls_loc <<
"\n"
3620 <<
"Available" <<
"\n"
3621 # if CFG_USE_OPENSSL_API_1_1
3622 <<
"Compiled for OpenSSL API 1.1" <<
"\n"
3623 # endif // !CFG_USE_OPENSSL_API_1_1
3624 #else // CFG_USE_TLS
3625 <<
"Not available" <<
"\n"
3626 #endif // CFG_USE_TLS
3627 <<
"Compiled for: FLTK " << FL_MAJOR_VERSION <<
"."
3628 << FL_MINOR_VERSION <<
"." << FL_PATCH_VERSION <<
"\n"
3629 #if CFG_CMPR_DISABLE
3630 <<
"Compression disabled" <<
"\n"
3631 #else // CFG_CMPR_DISABLE
3632 <<
"Compression available"
3635 # endif // CFG_USE_ZLIB
3637 #endif // CFG_CMPR_DISABLE
3638 <<
"Build: " << BDATE
3640 <<
"Problem description (in english):" <<
"\n\n"
3642 subjectString <<
"[" << CFG_NAME <<
"] "
3643 <<
"Bug report (...)"
3645 contentString << S(
"Report bug to:") <<
"\n"
3648 << S(
"Use the following subject line and replace")
3649 <<
" '...' " << S(
"with a summary") <<
":\n"
3650 << subjectString.str() <<
"\n\n"
3651 << S(
"Use the following skeleton:") <<
"\n"
3652 <<
"------------------------------------------------------\n"
3653 << configString.str()
3654 <<
"------------------------------------------------------\n"
3659 SC("Do not use characters for the translation that cannot be converted to")
3660 SC("the ISO 8859-1 character set for this item.")
3661 SC("Leave the original
string in place if in doubt.")
3662 titleString << S("Bug report") << std::flush;
3674 const std::
string& ts = titleString.str();
3675 const std::
string& cs = contentString.str();
3676 const std::
string&
config = configString.str();
3677 const std::
string& subject = subjectString.str();
3680 len = std::strlen(CFG_MAINTAINER);
3681 p = new
char[++len];
3682 std::strncpy(p, CFG_MAINTAINER, len);
3683 p[len - (
size_t) 1] = 0;
3685 q = std::strstr(p, "mailto:");
3701 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3706 title = gui_utf8_iso(ts.c_str());
3710 new BugreportWindow(title, cs.c_str());
3714 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3716 new BugreportWindow(ts.c_str(), cs.c_str());
3717 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3725 void MainWindow::license_cb_i(
void)
3727 std::ostringstream titleString;
3731 SC("Do not use characters for the translation that cannot be converted to")
3732 SC("the ISO 8859-1 character set for this item.")
3733 SC("Leave the original
string in place if in doubt.")
3734 titleString << S("License") << std::flush;
3746 const std::
string& ts = titleString.str();
3749 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3754 title = gui_utf8_iso(ts.c_str());
3758 new LicenseWindow(title);
3762 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3764 new LicenseWindow(ts.c_str());
3765 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3772 void MainWindow::console_cb_i(
void)
3774 if(NULL == protocolConsole)
3777 SC("Do not use characters for the translation that cannot be converted to")
3778 SC("the ISO 8859-1 character set for this item.")
3779 SC("Leave the original
string in place if in doubt.")
3780 protocolConsole = new ProtocolConsole(S("Protocol console"));
3789 void MainWindow::rot13_cb_i(
void)
3792 Fl_Text_Buffer* newdata =
new Fl_Text_Buffer(0, 0);
3794 if(NULL == currentGroup)
3796 SC(
"Do not use non-ASCII for the translation of this item")
3797 fl_message_title(S("Error"));
3798 fl_alert("%s", S("No group selected"));
3800 else if(NULL == currentArticleHE)
3802 SC(
"Do not use non-ASCII for the translation of this item")
3803 fl_message_title(S("Error"));
3804 fl_alert("%s", S("No article selected"));
3819 olddata = currentArticle->text();
3823 newdata->text(olddata);
3824 articleUpdate(newdata);
3826 std::free((
void*) olddata);
3837 void MainWindow::msau_cb_i(
void)
3842 if(NULL == currentGroup)
3844 SC(
"Do not use non-ASCII for the translation of this item")
3845 fl_message_title(S("Error"));
3846 fl_alert("%s", S("No group selected"));
3848 else if(NULL == currentArticleHE)
3850 SC(
"Do not use non-ASCII for the translation of this item")
3851 fl_message_title(S("Error"));
3852 fl_alert("%s", S("No article selected"));
3856 ti = articleTree->first_selected_item();
3863 ti->labelfont(FL_HELVETICA_BOLD);
3870 ti->labelfont(FL_HELVETICA);
3874 articleTree->redraw();
3875 groupListUpdateEntry(group_list_index);
3883 void MainWindow::mssar(Fl_Tree_Item* ti)
3894 ti->labelfont(FL_HELVETICA);
3898 for(i = 0; ti->children() > i; ++i)
3900 mssar(ti->child(i));
3905 void MainWindow::mssar_cb_i(
void)
3909 if(NULL == currentGroup)
3911 SC(
"Do not use non-ASCII for the translation of this item")
3912 fl_message_title(S("Error"));
3913 fl_alert("%s", S("No group selected"));
3917 ti = articleTree->first_selected_item();
3918 if(NULL == currentArticleHE || NULL == ti)
3920 SC(
"Do not use non-ASCII for the translation of this item")
3921 fl_message_title(S("Error"));
3922 fl_alert("%s", S("No article selected"));
3934 ti = articleTree->first_selected_item();
3937 articleTree->close(ti);
3941 groupListUpdateEntry(group_list_index);
3942 UI_STATUS(S(
"Marked all articles in subthread read."));
3951 void MainWindow::maar_cb_i(
void)
3956 if(stateMachine(EVENT_A_MAAR))
3958 if(NULL != currentGroup)
3961 for(ti = articleTree->first()->next(); ti; ti = articleTree->next(ti))
3963 ti->labelfont(FL_HELVETICA);
3965 articleTree->redraw();
3969 if(currentGroup->lwm && currentGroup->hwm >= currentGroup->lwm)
3972 for(a = currentGroup->hwm; a >= currentGroup->lwm; --a)
3979 groupListUpdateEntry(group_list_index);
3980 UI_STATUS(S(
"Marked all articles in group read."));
3983 if(!stateMachine(EVENT_A_MAAR_EXIT))
3985 PRINT_ERROR(
"Error in main window state machine");
3994 void MainWindow::magar_cb_i(
void)
4002 if(stateMachine(EVENT_A_MAGAR))
4005 fl_message_title(S(
"Warning"));
4006 rv = fl_choice(
"%s", S(
"No"),
4008 S(
"Really mark all groups read?"));
4012 if(NULL != currentGroup)
4014 for(ti = articleTree->first()->next(); ti;
4015 ti = articleTree->next(ti))
4017 ti->labelfont(FL_HELVETICA);
4019 articleTree->redraw();
4023 for(i = 0; group_num > i; ++i)
4026 g = &subscribedGroups[i];
4027 if(g->lwm && g->hwm >= g->lwm)
4030 for(a = g->hwm; a >= g->lwm; --a)
4036 groupListUpdateEntry(i);
4038 UI_STATUS(S(
"Marked all articles in all groups read."));
4041 if(!stateMachine(EVENT_A_MAGAR_EXIT))
4043 PRINT_ERROR(
"Error in main window state machine");
4052 void MainWindow::aselect_cb_i(
void)
4054 Fl_Tree_Item* ti = articleTree->callback_item();
4056 switch(articleTree->callback_reason())
4058 case FL_TREE_REASON_OPENED:
4065 ti->labelfont(FL_HELVETICA);
4068 scrollTree(UI_SCROLL_TOP, ti);
4071 case FL_TREE_REASON_CLOSED:
4074 if(checkTreeBranchForUnread(ti))
4077 ti->labelfont(FL_HELVETICA_BOLD);
4081 case FL_TREE_REASON_SELECTED:
4086 if(NULL == ti->user_data())
4088 PRINT_ERROR(
"No data associated with selected article item");
4093 if(stateMachine(EVENT_A_PREPARE))
4096 if(ti->is_open() || !checkTreeBranchForUnread(ti))
4100 ti->labelfont(FL_HELVETICA);
4103 lastArticleHE = currentArticleHE;
4107 articleSelect(UI_CB_START);
4109 scrollTree(UI_SCROLL_MIDDLE, ti);
4112 articleTree->store_current(ti);
4117 articleTree->select_former();
4134 void MainWindow::stripAngleAddress(
char* from)
4142 p = std::strrchr(from, (
int)
'<');
4144 q = std::strrchr(from, (
int)
'>');
4145 if(NULL != p && NULL != q && q > p + 1)
4148 for(i = 0; i < (std::size_t) (p - from); ++i)
4150 if(
' ' != from[i]) { strip =
true;
break; }
4155 if(
' ' == *(p - 1)) { --p; }
4162 std::memmove((
void*) from, (
void*) (p + 1), (std::size_t) (q - p));
4171 void MainWindow::sendEmail(
void)
4173 const char* recipient;
4174 const char* subject;
4175 const char* body = NULL;
4192 if(NULL == currentGroup)
4194 SC(
"Do not use non-ASCII for the translation of this item")
4195 fl_message_title(S("Error"));
4196 fl_alert("%s", S("No group selected"));
4198 else if(NULL == currentArticleHE)
4200 SC(
"Do not use non-ASCII for the translation of this item")
4201 fl_message_title(S("Error"));
4202 fl_alert("%s", S("No article selected"));
4206 recipient = currentArticleHE->header->reply2;
4207 if(NULL == recipient) { recipient = currentArticleHE->header->from; }
4208 if(NULL == recipient)
4218 if(NULL == recipient) { invalid = 1; }
4222 p = std::strrchr(recipient, (
int)
'.');
4226 if(!std::strcmp(p,
".test")) { invalid = 1; }
4227 if(!std::strcmp(p,
".example")) { invalid = 1; }
4228 if(!std::strcmp(p,
".invalid")) { invalid = 1; }
4229 if(!std::strcmp(p,
".localhost")) { invalid = 1; }
4234 hdr = currentArticleHE->header;
4235 t = currentArticle->text();
4239 while(
'_' != t[i++]);
4240 while(
'|' != t[i++]);
4241 while(
'|' != t[i++]);
4249 sig_delim = std::strstr(r,
"\n-- \n");
4250 if(NULL == sig_delim) {
break; }
4251 else { sig = r = &sig_delim[1]; }
4253 if(NULL != sig) { sig[0] = 0; }
4255 len = std::strlen(hdr->
from);
4256 from =
new char[++len];
4258 stripAngleAddress(
from);
4266 subject = currentArticleHE->header->subject;
4267 s =
new char[std::strlen(
subject) + (std::size_t) 5];
4268 std::strcpy(s,
"Re: ");
4269 std::strcat(s, gui_check_re_prefix(
subject));
4271 q = std::strstr(s,
"(was:");
4276 if(std::strchr(q, (
int)
')'))
4279 if(
' ' == *(--q)) { *q = 0; }
4288 if(std::strchr(
subject, 0x27)) { warn = 1; }
4290 if(!warn && NULL != body)
4294 if(std::strchr(body, 0x27)) { warn = 1; }
4298 SC(
"Do not use non-ASCII for the translation of this item")
4299 fl_message_title(S("Note"));
4301 S("APOSTROPHE converted to\nRIGHT SINGLE QUOTATION MARK"));
4307 SC(
"Do not use non-ASCII for the translation of this item")
4308 fl_message_title(S("Error"));
4309 fl_alert("%s", S("Starting e-mail client failed"));
4312 std::free((
void*) body);
4313 std::free((
void*) t);
4319 SC(
"Do not use non-ASCII for the translation of this item")
4320 fl_message_title(S("Error"));
4321 fl_alert("%s", S("Invalid e-mail address"));
4332 void MainWindow::ascrolldown_cb(
bool scroll)
4351 if(stateMachine(EVENT_SCROLL_NEXT))
4357 if(NULL != currentArticle && text->buffer() == currentArticle)
4359 r = text->count_lines(0, text->buffer()->length(),
true);
4362 for(i = 0; i < r; ++i)
4364 if(text->position_to_xy(p, &x, &y))
4366 if(0 > f) { l = f = i; }
4369 p = text->skip_lines(p, 1,
true);
4371 if(0 > f) { f = 0; l = 0; }
4377 std::printf(
"-----------------------------\n");
4378 std::printf(
"Rows : %d\n", r);
4379 std::printf(
"Current row : %d\n", currentLine);
4380 std::printf(
"First in view: %d\n", f);
4381 std::printf(
"Last in view : %d\n", l);
4382 std::printf(
"Rows in view : %d\n", riv);
4390 scrollto = currentLine + riv - 2;
4391 if(scrollto < r - 1)
4394 text->scroll(scrollto + 1, 0);
4406 fi = articleTree->first_selected_item();
4409 fi = articleTree->first();
4410 if(fi == articleTree->root()) { fi = articleTree->next(fi); }
4413 if(NULL == fi->user_data()) { fi = NULL; }
4422 while(articleTree->root() != oi)
4424 if(!articleTree->open(oi)) { articleTree->open(oi, 1); }
4425 for(i = 0; i < articleTree->root()->children(); ++i)
4427 if(articleTree->root()->child(i) == oi)
4433 if(abort) {
break; }
4434 oi = articleTree->prev(oi);
4437 articleTree->deselect(fi, 0);
4438 articleTree->set_item_focus(ti);
4439 articleTree->select(ti, 1);
4443 ti = articleTree->next(ti);
4444 if(NULL == ti && !wrap)
4448 ti = articleTree->first();
4449 if(ti == articleTree->root()) { ti = articleTree->next(ti); }
4453 if(!stateMachine(EVENT_SCROLL_NEXT_EXIT))
4455 PRINT_ERROR(
"Error in main window state machine");
4471 void MainWindow::updateServer(
int action)
4474 SC("Do not use characters for the translation that cannot be converted to")
4475 SC("the ISO 8859-1 character set for this item.")
4476 SC("Leave the original
string in place if in doubt.")
4477 const
char* titleString = S("Server configuration");
4481 ServerCfgWindow* scw = NULL;
4482 ServerConfig* sc = NULL;
4483 const
char* user = NULL;
4484 const
char* pass = NULL;
4487 if(UI_CB_START == action)
4490 if(!stateMachine(EVENT_SERVER)) { rv = 1; }
4495 SC(
"Do not use non-ASCII for the translation of this item")
4496 fl_message_title(S("Note"));
4497 SC("Line breaks are inserted with \n")
4499 S("Warning:\nGroup states are lost if the server is changed."));
4502 sc = new ServerConfig;
4509 #if CFG_USE_XSI && !CFG_NLS_DISABLE
4514 title = gui_utf8_iso(titleString);
4517 scw =
new ServerCfgWindow(sc, title);
4520 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
4521 scw =
new ServerCfgWindow(sc, titleString);
4522 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
4526 PRINT_ERROR(
"Fatal error while creating server config window");
4531 if(0 < scw->process())
4534 UI_STATUS(S(
"Update server configuration ..."));
4553 else { cancel = 1; }
4574 UI_STATUS(S(
"Updating server configuration failed."));
4591 if(UI_AUTH_USER == sc->auth)
4597 SC(
"Do not use non-ASCII for the translation of this item")
4598 fl_message_title(S("Note"));
4599 rv = fl_choice("%s", S("No"),
4601 S("Store the password
from the subsequent request?"));
4612 SC(
"Do not use non-ASCII for the translation of this item")
4613 fl_message_title(S("Warning"));
4614 fl_alert("%s", S("Empty password is not supported"));
4625 SC(
"Do not use non-ASCII for the translation of this item")
4626 fl_message_title(S("Note"));
4627 rv = fl_choice("%s", S("No"),
4629 S("Ask server for group subscription proposals?"));
4633 groupListGetProposal(UI_CB_START);
4637 UI_STATUS(S(
"No groups subscribed yet."));
4645 groupListRefresh(UI_CB_START);
4648 if(NULL != sc) {
delete sc; }
4649 if(!stateMachine(EVENT_SERVER_EXIT))
4651 PRINT_ERROR(
"Error in main window state machine");
4661 void MainWindow::groupSubscribe(
int action)
4664 std::size_t labelcount;
4666 std::size_t i, ii, j;
4671 int fake_empty_response = 0;
4674 if(UI_CB_START == action)
4676 if(!stateMachine(EVENT_SUBSCRIBE)) { rv = 1; }
4680 UI_STATUS(S(
"Receiving group list ..."));
4694 if(!rv && UI_CB_CONTINUE == action)
4701 UI_STATUS(S(
"Receiving group labels ..."));
4705 if(0 > rv) { fake_empty_response = 1; }
4708 if(0 > rv && UI_CB_FINISH == action) { fake_empty_response = 1; }
4710 if (fake_empty_response)
4726 UI_STATUS(S(
"Downloading group information failed."));
4736 UI_STATUS(S(
"Group information received."));
4739 SC("Do not use characters for the translation that cannot be")
4740 SC("converted to the ISO 8859-1 character set for this item.")
4741 SC("Leave the original
string in place if in doubt.")
4742 subscribeWindow = new SubscribeWindow(S("Subscribe"),
4746 UI_STATUS(S("Process group information ..."));
4747 subscribeWindow->hide();
4749 for(i = 0; i < groupcount; ++i)
4756 name = grouplist[i].name;
4757 num = grouplist[i].eac;
4759 for(j = 0; j < labelcount; ++j)
4761 if(!strcmp(labels[j].name, name))
4768 label = labels[j].label;
4773 PRINT_ERROR(
"Invalid encoding of group description");
4775 if(NULL != label) { free_label = 1; }
4782 do {
if(
'.' == name[ii]) { name[ii] =
'/'; } }
4784 subscribeWindow->add(name, num, label);
4785 if(free_label) {
core_free((
void*) label); }
4790 subscribeWindow->collapseAll();
4791 subscribeWindow->show();
4792 UI_STATUS(S(
"Group information processed."));
4798 if(!stateMachine(EVENT_SUBSCRIBE_EXIT))
4800 PRINT_ERROR(
"Error in main window state machine");
4815 if(lwm && hwm && hwm >= lwm)
4824 for(i = info->
last; i >= info->
first; --i)
4826 if(i >= lwm && i <= hwm) {
if(res) { --res; } }
4839 void MainWindow::groupListUpdateEntry(std::size_t i)
4841 std::ostringstream groupString;
4847 if((std::size_t) 500 >= i)
4850 groupCAC(&subscribedGroups[i]);
4853 eac = subscribedGroups[i].eac;
4854 ur = groupGetUnreadNo(subscribedGroups[i].lwm, subscribedGroups[i].hwm,
4855 group_list[i].info);
4857 if(ur) { fcs =
"@b"; }
else { fcs =
"@."; }
4858 groupString << fcs << group_list[i].
name
4859 <<
" (" << ur <<
" / " << eac <<
")" << std::flush;
4870 const std::string& gs = groupString.str();
4873 if(++i > (std::size_t) groupList->size())
4876 groupList->add(gs.c_str(), NULL);
4881 groupList->text((
int) i, gs.c_str());
4890 int MainWindow::groupStateMerge(
void)
4900 SC(
"Do not use non-ASCII for the translation of this item")
4901 fl_message_title(S("Error"));
4902 fl_alert("%s", S("Exporting group states failed"));
4917 void MainWindow::groupListGetProposal(
int action)
4920 char* grouplist_raw;
4923 if(UI_CB_START == action)
4926 if(!stateMachine(EVENT_GL_PROPOSAL)) { rv = 1; }
4930 UI_STATUS(S(
"Get group subscription proposals ..."));
4949 UI_STATUS(S(
"Receiving proposed groups failed."));
4958 rv = gui_populate_group_list(grouplist_raw);
4961 PRINT_ERROR(
"Updating list of subscribed groups failed");
4965 groupListRefresh(UI_CB_START);
4967 if(!stateMachine(EVENT_GL_PROPOSAL_EXIT))
4969 PRINT_ERROR(
"Error in main window state machine");
4979 void MainWindow::groupListRefresh(
int action)
4985 if(UI_CB_START == action)
4988 if(!stateMachine(EVENT_GL_REFRESH)) { rv = 1; }
4991 rv = groupStateMerge();
4995 UI_STATUS(S(
"Refreshing subscribed groups ..."));
4997 groupRefresh_cb_state = groupList->value();
4999 UI_CB_COOKIE_GROUPINFO1);
5012 if(!rv && UI_CB_CONTINUE == action)
5015 if(NULL != subscribedGroups)
5024 for(i = 0; i < group_num; ++i) { groupListUpdateEntry(i); }
5026 if(group_num && NULL != currentGroup)
5029 UI_CB_COOKIE_GROUPINFO2);
5034 if(!rv && UI_CB_FINISH == action)
5051 currentGroup = NULL;
5052 UI_STATUS(S(
"Refreshing subscribed groups failed."));
5056 if(!group_num || unsub)
5061 currentGroup = NULL;
5066 groupList->value(groupRefresh_cb_state);
5069 UI_STATUS(S(
"Subscribed groups refreshed."));
5073 if(!stateMachine(EVENT_GL_REFRESH_EXIT))
5075 PRINT_ERROR(
"Error in main window state machine");
5085 void MainWindow::groupSelect(
int action,
int index)
5089 if(UI_CB_START == action)
5091 if(!index || !stateMachine(EVENT_G_SELECT))
5093 if(NULL != currentGroup)
5096 if((std::size_t) INT_MAX > group_list_index)
5098 groupList->value((
int) group_list_index + 1);
5112 if((std::size_t) INT_MAX > group_list_index)
5114 group_old = (int) group_list_index + 1;
5117 group_list_index = (std::size_t) index;
5118 if(--group_list_index < group_num)
5120 UI_STATUS(S(
"Set new current group ..."));
5122 groupSelect_cb_state = groupList->value();
5124 UI_CB_COOKIE_GROUP);
5144 UI_STATUS(S(
"Setting new current group failed."));
5149 groupList->select(group_new, 0);
5153 group_list_index = group_old - 1;
5154 groupList->value(group_old);
5156 if(stateMachine(EVENT_AT_REFRESH))
5158 if(!stateMachine(EVENT_AT_REFRESH_EXIT))
5160 PRINT_ERROR(
"Error in main window state machine");
5173 groupCAC(currentGroup);
5177 lastArticleHE = NULL;
5178 currentArticleHE = NULL;
5179 updateArticleTree(UI_CB_START);
5181 if(!stateMachine(EVENT_G_SELECT_EXIT))
5183 PRINT_ERROR(
"Error in main window state machine");
5197 if(NULL != g && 0 < i--)
5200 if(g->hwm >= g->lwm && g->eac)
5205 if(g->hwm - g->lwm > diff) { g->lwm = g->hwm - diff; }
5214 void MainWindow::clearTree(
void)
5220 articleTree->item_labelfont(FL_HELVETICA);
5221 articleTree->clear();
5222 ti = articleTree->add(S(
"No articles"));
5223 if(NULL != ti) { ti->deactivate(); }
5224 articleTree->redraw();
5227 lastArticleHE = NULL;
5229 currentArticleHE = NULL;
5231 if(startup) { startup =
false; }
5234 tb =
new Fl_Text_Buffer(0, 0);
5252 void MainWindow::scrollTree(ui_scroll position, Fl_Tree_Item* ti)
5254 bool old_tree_widget =
true;
5257 #ifdef FL_ABI_VERSION
5258 # if 10303 <= FL_ABI_VERSION
5260 articleTree->hposition(0);
5261 articleTree->calc_tree();
5262 articleTree->hposition(0);
5263 old_tree_widget =
false;
5264 # endif // 10303 <= FL_ABI_VERSION
5265 #endif // FL_ABI_VERSION
5269 articleTree->vposition(0);
5271 articleTree->redraw();
5272 articleTree->not_drawn();
5274 while(!articleTree->drawn()) { Fl::wait(0.10); }
5279 #ifdef FL_ABI_VERSION
5280 # if 10303 <= FL_ABI_VERSION
5282 gui_set_default_font();
5284 int xmax = ti->draw_item_content(0);
5285 int scroll = xmax - (articleTree->x() + articleTree->w());
5288 if(articleTree->is_vscroll_visible())
5291 int w_sb = articleTree->scrollbar_size();
5292 if (0 == w_sb) { w_sb = Fl::scrollbar_size(); }
5298 int left = ti->x() - articleTree->x();
5304 articleTree->hposition(scroll);
5307 # endif // 10303 <= FL_ABI_VERSION
5308 #endif // FL_ABI_VERSION
5315 articleTree->show_item_top(ti);
5318 case UI_SCROLL_MIDDLE:
5320 articleTree->show_item_middle(ti);
5323 case UI_SCROLL_BOTTOM:
5325 articleTree->show_item_bottom(ti);
5328 case UI_SCROLL_NONE:
5336 articleTree->redraw();
5344 bool MainWindow::checkTreeBranchForUnread(Fl_Tree_Item* ti)
5353 for(i = 0; i < c; ++i)
5356 if(FL_HELVETICA_BOLD == ti->child(i)->labelfont()) { res =
true; }
5360 if(checkTreeBranchForUnread(ti->child(i))) { res =
true; }
5362 if(
true == res) {
break; }
5374 bool MainWindow::checkTreeBranchForItem(Fl_Tree_Item* ti, Fl_Tree_Item* sti)
5383 for(i = 0; i < c; ++i)
5386 if(ti->child(i) == sti) { res =
true; }
5390 if(checkTreeBranchForItem(ti->child(i), sti)) { res =
true; }
5392 if(
true == res) {
break; }
5421 Fl_Tree_Item* MainWindow::addTreeNodes(Fl_Tree_Item* cti,
5424 static const char t[] =
" | ";
5425 std::size_t t_len =
sizeof(t);
5436 unsigned long int l_raw;
5438 #endif // USE_LINE_COUNT
5439 #if USE_ARTICLE_NUMBER
5441 #endif // USE_ARTICLE_NUMBER
5442 std::size_t l_len = 0;
5443 std::size_t a_len = 0;
5444 Fl_Tree_Item* res = NULL;
5445 Fl_Tree_Item* tmp = NULL;
5446 Fl_Tree_Item* nti = NULL;
5454 bool child_of_root_node =
false;
5467 articleTree->item_labelfgcolor(FL_FOREGROUND_COLOR);
5470 articleTree->item_labelfont(FL_HELVETICA_BOLD);
5473 if(articleTree->root() == cti) { child_of_root_node =
true; }
5480 s_len = std::strlen(s);
5482 f_len = t_len + std::strlen(f);
5485 if(rv) { d_len = 0; }
else { d_len = t_len + (std::size_t) 20; }
5489 l_len = t_len + (std::size_t) 11;
5490 #else // USE_LINE_COUNT
5492 #endif // USE_LINE_COUNT
5493 #if USE_ARTICLE_NUMBER
5505 else { a_len += t_len; }
5506 #else // USE_ARTICLE_NUMBER
5508 #endif // USE_ARTICLE_NUMBER
5510 ss =
new char[s_len + f_len + d_len + l_len + a_len + (std::size_t) 1];
5514 ii = 0;
while(s[ii])
5521 if (0x09 == (
int) s_tmp) { ss[ssi++] =
' '; }
5522 else { ss[ssi++] = s_tmp; }
5526 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5529 f_tmp =
new char[f_len + (std::size_t) 1];
5530 std::strcpy(f_tmp, f);
5531 stripAngleAddress(f_tmp);
5532 ii = 0;
while(f_tmp[ii]) { ss[ssi++] = f_tmp[ii++]; }
5538 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5539 ii = 0;
while(d[ii]) { ss[ssi++] = d[ii++]; }
5544 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5545 ii = 0;
while(l[ii]) { ss[ssi++] = l[ii++]; }
5546 #endif // USE_LINE_COUNT
5549 #if USE_ARTICLE_NUMBER
5550 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5551 ii = 0;
while(a[ii]) { ss[ssi++] = a[ii++]; }
5552 #endif // USE_ARTICLE_NUMBER
5562 if(child_of_root_node)
5566 for(iii = 0; iii < cti->children(); ++iii)
5575 if(NULL != h2->
refs)
5577 if(!strcmp(h2->
refs[0], h->
refs[0]))
5579 rti = cti->child(iii);
5585 if(NULL == rti) { rti = cti; }
5586 nti = articleTree->add(rti, ss);
5588 else { nti = articleTree->add(cti, ss); }
5595 for(rti = articleTree->next(articleTree->first());
5596 rti; rti = articleTree->next(rti))
5606 if(rn >= n) { match =
true; }
5611 if(rn < n) { match =
true; }
5621 if(rd >= d_raw) { match =
true; }
5626 if(rd < d_raw) { match =
true; }
5631 nti = articleTree->insert_above(rti, ss);
5635 if(NULL == rti) { nti = articleTree->add(articleTree->root(), ss); }
5638 nti->user_data((
void*) che->
child[i]);
5647 if(0 < score) { nti->usericon(&pm_score_up); }
5651 nti->usericon(&pm_reply_to_own);
5656 nti->usericon(&pm_score_down);
5667 nti->labelfont(FL_HELVETICA);
5675 if(NULL != tmp) { res = tmp; }
5678 if(group_list[group_list_index].last_viewed == che->
child[i]->
anum)
5687 groupListUpdateEntry(group_list_index);
5696 void MainWindow::updateTree(
void)
5701 Fl_Tree_Item* child_of_root;
5702 Fl_Tree_Item* sti = NULL;
5704 bool unread_articles_present;
5707 bool recalculate =
true;
5710 articleTree->update_in_progress(
true);
5713 articleTree->redraw();
5714 articleTree->not_drawn();
5716 while(!articleTree->drawn()) { Fl::wait(0.10); }
5719 rti = articleTree->root();
5722 articleTree->add(
"X");
5723 rti = articleTree->root();
5726 articleTree->clear_children(rti);
5729 articleTree->redraw();
5730 articleTree->not_drawn();
5732 while(!articleTree->drawn()) { Fl::wait(0.10); }
5736 if(!rv) { sti = addTreeNodes(rti, che); }
5745 recalculate =
false;
5746 rv = rti->children();
5747 for(i = 0; i < rv; ++i)
5749 if(FL_HELVETICA_BOLD == rti->child(i)->labelfont())
5751 unread_articles_present =
true;
5755 unread_articles_present
5756 = checkTreeBranchForUnread(rti->child(i));
5758 if(!unread_articles_present)
5761 if( rti->child(i) == sti
5762 || checkTreeBranchForItem(rti->child(i), sti) )
5767 articleTree->remove(rti->child(i));
5774 if(!rti->children())
5776 ti = articleTree->add(S(
"No articles"));
5780 ti->labelfont(FL_HELVETICA);
5781 ti->user_data(NULL);
5788 rv = rti->children();
5789 for(i = 0; i < rv; ++i)
5791 unread_articles_present = checkTreeBranchForUnread(rti->child(i));
5792 if(unread_articles_present)
5794 rti->child(i)->labelfont(FL_HELVETICA_BOLD);
5804 while(NULL != (ti = articleTree->next(ti)))
5810 while(articleTree->root() != oi)
5812 if(!articleTree->open(oi)) { articleTree->open(oi, 1); }
5813 for(i = 0; i < articleTree->root()->children(); ++i)
5815 if(articleTree->root()->child(i) == oi)
5821 if(abort) {
break; }
5822 oi = articleTree->prev(oi);
5825 articleTree->set_item_focus(ti);
5826 articleTree->select(ti, 1);
5827 Fl::focus(articleTree);
5840 child_of_root = rti->child(rti->children() - 1);
5845 child_of_root = rti->child(0);
5847 scrollTree(UI_SCROLL_BOTTOM, child_of_root);
5848 articleTree->set_item_focus(child_of_root);
5849 Fl::focus(articleTree);
5852 currentArticle->text(
"");
5853 currentStyle->text(
"");
5855 articleTree->redraw();
5857 articleTree->update_in_progress(
false);
5865 void MainWindow::updateArticleTree(
int action)
5870 if(UI_CB_START == action)
5872 if(!stateMachine(EVENT_AT_REFRESH)) { rv = 1; }
5877 #ifdef FL_ABI_VERSION
5878 # if 10303 <= FL_ABI_VERSION
5880 articleTree->hposition(0);
5881 # endif // 10303 <= FL_ABI_VERSION
5882 #endif // FL_ABI_VERSION
5888 if(!currentGroup->eac) { rv = 2; }
5892 ai = currentGroup->lwm;
5893 UI_STATUS(S(
"Update article tree ..."));
5896 ai_range.
first = currentGroup->lwm;
5897 ai_range.
last = currentGroup->hwm;
5898 ai_range.
next = NULL;
5921 if(0 >= rv || 2 == rv)
5942 if(UI_CB_FINISH == action)
5953 (std::size_t) currentGroup->hwm - currentGroup->lwm);
5955 if(currentGroup->hwm == ai++)
5964 if(0 > rv) { state = -1; }
5979 PRINT_ERROR(
"Adding article to hierarchy failed");
5990 groupList->value(groupSelect_cb_state);
5992 if(!stateMachine(EVENT_AT_REFRESH_EXIT))
5994 PRINT_ERROR(
"Error in main window state machine");
6016 UI_STATUS(S(
"Updating article tree failed."));
6021 PRINT_ERROR(
"Invalid state while updating article tree");
6023 UI_STATUS(S(
"Updating article tree failed."));
6035 void MainWindow::articleUpdate(Fl_Text_Buffer* article)
6037 static bool init =
true;
6039 const char* url[] = {
"http://",
"https://",
"ftp://",
"nntp://",
6040 "file://",
"news:",
"mailto:", NULL };
6041 const std::size_t url_len[] = { 7, 8, 6, 7, 7, 5, 7 };
6042 const char bold =
'A';
6043 const char sig =
'B';
6044 const char cit =
'C';
6045 const char link =
'D';
6046 const char plain =
'E';
6047 const char l1 =
'F';
6048 const char l2 =
'G';
6049 const char l3 =
'H';
6050 const char l4 =
'I';
6051 Fl_Text_Buffer* ca = currentArticle;
6056 std::size_t iii = 0;
6061 bool references =
false;
6065 bool signature =
false;
6066 bool citation =
false;
6067 bool hyperlink =
false;
6069 bool cl_lock =
false;
6074 hyperlinkStyle = (
unsigned int) (
unsigned char) link;
6079 PRINT_ERROR(
"Article update request without content ignored (bug)");
6082 gui_check_article(article);
6083 currentArticle = article;
6084 text->buffer(currentArticle);
6086 if(ca) {
delete ca; }
6089 gui_process_shy(currentArticle);
6092 if(currentStyle) {
delete currentStyle; }
6093 style = currentArticle->text();
6094 if(NULL == style) { len = 0; }
6095 else { len = std::strlen(style); }
6096 if(INT_MAX < len) { len = INT_MAX; }
6097 for(i = 0; i < len; ++i)
6099 if(
'\n' == style[i])
6115 if(
' ' == c || 0x09 == (
int) c ||
'>' == c ||
'"' == c)
6121 if(sol && (
'|' == style[i] ||
'!' == style[i]))
6123 if(!hyperlink) { citation =
true; }
6126 if(sol) { sol =
false; delim =
true; ss = 0; cl = 0; ii = 0; }
6135 for(iiii = i - ii; iiii < i; ++iiii)
6137 if(
'_' != currentArticle->byte_at((
int) iiii)) {
break; }
6141 for(iiii = 0; iiii <= ii; ++iiii)
6143 style[i - iiii] = plain;
6155 if(
'_' != style[i]) { hs = bold; }
else { hs = plain; }
6158 if(
'|' == style[i] && 79U <= iii) { ready =
true; }
6159 else if(
'_' == style[i]) { ++iii; }
6160 if(
':' == style[i]) { hs = plain; }
6162 if(0x1D == (
int) style[i]) { references =
true; }
6166 if(0x30 <= style[i] && 0x39 >= style[i]) { hs = link; }
6167 else { hs = plain; }
6174 if(
'-' == style[i] && !ii) { ss = 1; }
6175 if(
'-' == style[i] && 1U == ii && 1 == ss) { ss = 2; }
6176 if(
' ' == style[i] && 2U == ii && 2 == ss)
6179 if((
char) 0x0A == style[i + 1U])
6181 if(gui_last_sig_separator(&style[i + 1U]))
6183 style[i] = sig; style[i - 1U] = sig; style[i - 2U] = sig;
6190 while(NULL != url[url_i])
6192 if(!std::strncmp(&style[i], url[url_i], url_len[url_i]))
6203 if(
' ' == c || 0x09 == (
int) c ||
'<' == c ||
'"' == c)
6207 else { delim =
false; }
6213 if(
'>' == style[i]) { cl_lock =
false; }
6214 else { cl_lock =
true; }
6216 if(
'>' == style[i] && !cl_lock) { ++cl; }
6217 if(
'>' != style[i] &&
' ' != style[i] && (
char) 9 != style[i])
6221 if(4U < cl) { cl = 1; }
6224 case 1: { style[i] = l1;
break; }
6225 case 2: { style[i] = l2;
break; }
6226 case 3: { style[i] = l3;
break; }
6227 case 4: { style[i] = l4;
break; }
6228 default: { style[i] = plain;
break; }
6233 if(signature) { style[i] = sig; }
6234 if(citation && !signature) { style[i] = cit; }
6235 if(hyperlink) { style[i] = link; }
6238 currentStyle =
new Fl_Text_Buffer((
int) len, 0);
6239 if(NULL != style) { currentStyle->text(style); }
6240 std::free((
void*) style);
6243 if(init) { init =
false; }
6247 text->highlight_data(currentStyle, styles, styles_len,
'A', NULL, NULL);
6251 if (1 == currentArticle->findchar_forward(0, 0x1DU, &pos))
6253 currentArticle->replace(pos, pos + 1,
" ");
6263 return(gui_print_header_fields(h));
6271 void MainWindow::articleSelect(
int action)
6276 const char* p = NULL;
6277 const char* q = NULL;
6280 bool overview =
false;
6281 bool process =
false;
6284 if(NULL == currentArticleHE)
6287 SC(
"Do not use non-ASCII for the translation of this item")
6288 fl_message_title(S("Error"));
6289 fl_alert("%s", "Fatal error detected in 'articleSelect()' (bug)");
6297 if(UI_CB_START == action)
6300 if(!stateMachine(EVENT_A_SELECT)) { rv = 1; }
6301 else if(currentArticleHE)
6341 wrapMode = Fl_Text_Display::WRAP_NONE;
6342 text->wrap_mode(wrapMode, 0);
6344 if(!overview) { q = p; }
6349 eoh = std::strstr(raw,
"\r\n\r\n");
6362 currentArticleHE->anum, p);
6363 if(0 > rv) { process =
false; }
6370 UI_STATUS(S(
"Download of article failed."));
6373 currentArticle->text(
"");
6374 currentStyle->text(
"");
6379 UI_STATUS(S(
"Article successfully downloaded."));
6381 tb =
new Fl_Text_Buffer(0, 0);
6385 std::printf(
"\nArticle watermark ............: %lu\n",
6386 currentArticleHE->anum);
6387 std::printf(
"MIME version .................: %s\n",
6388 currentArticleHE->header->mime_v);
6389 std::printf(
"MIME content transfer encoding: %s\n",
6390 currentArticleHE->header->mime_cte);
6391 std::printf(
"MIME content type ............: %s\n",
6392 currentArticleHE->header->mime_ct);
6395 hdr = printHeaderFields(currentArticleHE->header);
6404 if(NULL != mimeData) {
delete mimeData; }
6405 mimeData =
new MIMEContent(currentArticleHE->header, q);
6407 gui_decode_mime_entities(tb, mimeData,
6408 currentArticleHE->header->msgid);
6412 group_list[group_list_index].last_viewed = currentArticleHE->anum;
6416 currentArticleHE->anum);
6417 groupListUpdateEntry(group_list_index);
6419 if(!process) { currentArticleHE = NULL; }
6423 currentSearchPosition = 0;
6425 if(!stateMachine(EVENT_A_SELECT_EXIT))
6427 PRINT_ERROR(
"Error in main window state machine");
6437 void MainWindow::viewMotd(
int action)
6440 std::ostringstream titleString;
6441 const char* motd = NULL;
6444 if(UI_CB_START == action)
6446 if(!stateMachine(EVENT_MOTD_VIEW)) { rv = 1; }
6450 UI_STATUS(S(
"Get message of the day ..."));
6467 if(0 > rv) {
UI_STATUS(S(
"Downloading message of the day failed.")); }
6474 UI_STATUS(S(
"Message of the day successfully downloaded."));
6486 SC("Do not use characters for the translation that cannot be")
6487 SC("converted to the ISO 8859-1 character set for this item.")
6488 SC("Leave the original
string in place if in doubt.")
6489 titleString << S("Message of the day") << std::flush;
6502 const std::
string& ts = titleString.str();
6505 #if CFG_USE_XSI && !CFG_NLS_DISABLE
6511 title = gui_utf8_iso(ts.c_str());
6515 new MotdWindow(motd, title);
6519 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
6521 new MotdWindow(motd, ts.c_str());
6522 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
6527 if(!stateMachine(EVENT_MOTD_VIEW_EXIT))
6529 PRINT_ERROR(
"Error in main window state machine");
6541 void MainWindow::viewArticle(
int action,
const char* mid)
6543 static const char debug_prefix[] =
"Try to fetch article: ";
6545 std::ostringstream titleString;
6546 const char* article;
6550 if(UI_CB_START == action)
6552 if(!stateMachine(EVENT_A_VIEW)) { rv = 1; }
6553 else if(NULL != mid)
6559 mid_a =
new char[std::strlen(mid) + (std::size_t) 3];
6561 std::strcpy(&mid_a[1], mid);
6562 std::strcat(mid_a,
">");
6566 len += std::strlen(debug_prefix);
6567 len += std::strlen(mid_a);
6568 sbuf =
new char[len + (std::size_t) 1];
6570 std::strcat(sbuf, debug_prefix);
6571 std::strcat(sbuf, mid_a);
6594 UI_STATUS(S(
"Downloading article failed."));
6595 SC(
"Do not use non-ASCII for the translation of this item")
6596 fl_message_title(S("Error"));
6597 fl_alert("%s", S("Article not found"));
6605 UI_STATUS(S(
"Article successfully downloaded."));
6609 SC("Do not use characters for the translation that cannot be")
6610 SC("converted to the ISO 8859-1 character set for this item.")
6611 SC("Leave the original
string in place if in doubt.")
6612 titleString << S("Article") << std::flush;
6625 const std::
string& ts = titleString.str();
6628 #if CFG_USE_XSI && !CFG_NLS_DISABLE
6634 title = gui_utf8_iso(ts.c_str());
6638 new ArticleWindow(article, title);
6642 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
6644 new ArticleWindow(article, ts.c_str());
6645 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
6649 if(!stateMachine(EVENT_A_VIEW_EXIT))
6651 PRINT_ERROR(
"Error in main window state machine");
6661 void MainWindow::viewSrc(
int action)
6664 std::ostringstream titleString;
6665 const char* article;
6667 if(UI_CB_START == action)
6669 if(!stateMachine(EVENT_SRC_VIEW)) { rv = 1; }
6670 else if(NULL != currentArticleHE)
6673 UI_STATUS(S(
"Get article source code ..."));
6690 if(0 > rv) {
UI_STATUS(S(
"Downloading article source code failed.")); }
6697 UI_STATUS(S(
"Article source code successfully downloaded."));
6701 SC("Do not use characters for the translation that cannot be")
6702 SC("converted to the ISO 8859-1 character set for this item.")
6703 SC("Leave the original
string in place if in doubt.")
6704 titleString << S("Article source code") << std::flush;
6717 const std::
string& ts = titleString.str();
6720 #if CFG_USE_XSI && !CFG_NLS_DISABLE
6726 title = gui_utf8_iso(ts.c_str());
6730 new ArticleSrcWindow(article, title);
6734 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
6736 new ArticleSrcWindow(article, ts.c_str());
6737 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
6741 if(!stateMachine(EVENT_SRC_VIEW_EXIT))
6743 PRINT_ERROR(
"Error in main window state machine");
6760 void MainWindow::articleCompose(
bool reply,
bool super)
6763 std::ostringstream titleString;
6766 const char* cq = NULL;
6773 Fl_Text_Buffer header;
6774 const char*
msgid = NULL;
6775 const char* ckey1 = NULL;
6776 const char* ckey = NULL;
6778 const char* datetime;
6779 bool headerOK =
true;
6783 unsigned int c = (
unsigned int)
'\n';
6785 const char* field_name;
6788 bool insertedMessageID =
false;
6794 if(!stateMachine(EVENT_COMPOSE)) {
return; }
6796 if(!groupList->value())
6798 SC(
"Do not use non-ASCII for the translation of this item")
6799 fl_message_title(S("Error"));
6800 fl_alert("%s", S("No group selected"));
6802 else if((reply || super) && NULL == currentArticleHE)
6804 SC(
"Do not use non-ASCII for the translation of this item")
6805 fl_message_title(S("Error"));
6806 fl_alert("%s", S("No article selected"));
6810 if(reply || super) { hdr = currentArticleHE->header; }
6816 if(reply && !super && NULL != hdr->
fup2)
6818 if(!std::strcmp(
"poster", hdr->
fup2))
6820 SC(
"Do not use non-ASCII for the translation of this item")
6821 fl_message_title(S("Warning"));
6822 rv = fl_choice("%s", S("Cancel"),
6825 S("Really execute Followup-To to poster?"));
6826 if(1 == rv) { sendEmail(); }
6827 if(!rv || 1 == rv) { abort =
true; }
6836 if(currentArticle->selected())
6839 p = currentArticle->selection_text();
6840 if(NULL != p) { cq = p; }
6845 p = currentArticle->text();
6849 while(
'_' != p[i++]);
6850 while(
'|' != p[i++]);
6851 while(
'|' != p[i++]);
6858 sig_delim = std::strstr(q,
"\n-- \n");
6859 if(NULL == sig_delim) {
break; }
6860 else { sig = q = &sig_delim[1]; }
6862 if(NULL != sig) { sig[0] = 0; }
6866 len = std::strlen(hdr->
from);
6867 from =
new char[++len];
6869 stripAngleAddress(
from);
6876 cq =
"Reason for cancel unknown.\n";
6896 header.append(
"Path: not-for-mail\n");
6897 if(std::strlen(fqdn))
6899 header.append(
"Message-ID: ");
6901 if(NULL ==
msgid) { headerOK =
false; }
6904 header.append(
msgid);
6905 insertedMessageID =
true;
6908 header.append(
"\n");
6912 SC(
"Do not use non-ASCII for the translation of this item")
6913 fl_message_title(S("Error"));
6914 fl_alert("%s", S("From: header field not configured"));
6919 field_name =
"From: ";
6921 std::strlen(field_name));
6922 if(NULL == field) { headerOK =
false; }
6925 header.append(field_name);
6926 header.append(field);
6927 header.append(
"\n");
6932 std::strlen(field_name));
6933 if(NULL == field2) { headerOK =
false; }
6936 if(std::strcmp(field, field2))
6938 SC(
"Do not use non-ASCII for the translation of this item")
6939 fl_message_title(S("Error"));
6940 fl_alert("%s", S("Supersede or cancel not allowed"));
6949 header.append("Newsgroups: ");
6950 if(!super && !reply) { header.append(currentGroup->name); }
6956 if(!super && NULL != hdr->
fup2)
6958 if(std::strcmp(
"poster", hdr->
fup2))
6960 SC(
"Do not use non-ASCII for the translation of this item")
6961 fl_message_title(S("Note"));
6962 fl_message("%s", S("Followup-To specified
groups executed"));
6963 header.append(hdr->
fup2);
6964 len += std::strlen(hdr->
fup2);
6974 if(i) { header.append(
","); }
6976 header.append(hdr->
groups[i]);
6977 len += std::strlen(hdr->
groups[i]);
6979 while(NULL != hdr->
groups[++i]);
6982 if((std::size_t) 998 < len) { headerOK =
false; }
6984 header.append(
"\n");
6985 header.append(
"Subject: ");
6991 header.append(
"Re: ");
7001 if(NULL == hdr->
msgid) { headerOK =
false; }
7004 header.append(
"cmsg cancel ");
7005 header.append(hdr->
msgid);
7008 header.append(
"\n");
7012 rv = header.search_forward(0,
"Subject:", &start, 1);
7016 if(0 < start) { c = header.char_at(start - 1); }
7017 if((
unsigned int)
'\n' == c)
7020 rv = header.findchar_forward(start, (
unsigned int)
'\n', &end);
7023 rv = header.search_forward(start,
"(was:", &pos, 0);
7026 header.remove(pos, end);
7029 if((
unsigned int)
' ' == header.char_at(pos - 1))
7031 header.remove(pos - 1, pos);
7039 header.append(
"Date: ");
7041 if(NULL == datetime) { headerOK =
false; }
7042 else { header.append(datetime); }
7043 header.append(
"\n");
7045 if(insertedMessageID)
7050 if(NULL != ckey1 || NULL != ckey)
7052 header.append(
"Cancel-Lock: ");
7053 if(NULL != ckey1) { header.append(ckey1); }
7054 if(NULL != ckey1 && NULL != ckey) { header.append(
" " ); }
7055 if(NULL != ckey) { header.append(ckey); }
7056 header.append(
"\n");
7065 header.append(
"Injection-Date: ");
7066 header.append(datetime);
7067 header.append(
"\n");
7074 if(NULL ==
msgid) { headerOK =
false; }
7079 header.append(
"Supersedes: ");
7080 header.append(
msgid);
7081 header.append(
"\n");
7085 header.append(
"Control: cancel ");
7086 header.append(
msgid);
7087 header.append(
"\n");
7089 if(insertedMessageID)
7094 if(NULL != ckey1 || NULL != ckey)
7096 header.append(
"Cancel-Key: ");
7097 if(NULL != ckey1) { header.append(ckey1); }
7098 if(NULL != ckey1 && NULL != ckey) { header.append(
" " ); }
7099 if(NULL != ckey) { header.append(ckey); }
7100 header.append(
"\n");
7109 field_name =
"Reply-To: ";
7111 std::strlen(field_name));
7112 if(NULL == field) { headerOK =
false; }
7115 header.append(field_name);
7116 header.append(field);
7117 header.append(
"\n");
7130 if(!(NULL == hdr->
refs && super))
7132 header.append(
"References: ");
7133 inspos = header.length();
7135 header.append(
"\n");
7139 header.insert(inspos, hdr->
msgid);
7140 len += std::strlen(hdr->
msgid);
7142 if(NULL != hdr->
refs)
7144 if(NULL != hdr->
refs[0])
7148 len += std::strlen(hdr->
refs[0]);
7151 while(NULL != hdr->
refs[i]) { ++i; }
7154 len += std::strlen(hdr->
refs[i]);
7158 header.insert(inspos,
" ");
7159 header.insert(inspos, hdr->
refs[i]);
7163 header.insert(inspos,
" ");
7164 header.insert(inspos, hdr->
refs[0]);
7170 header.append(
"Organization: ");
7172 header.append(
"\n");
7176 header.append(
"User-Agent: " CFG_NAME
"/" CFG_VERSION
7177 " (for " CFG_OS
")\n");
7182 header.append(
"MIME-Version: 1.0\n");
7184 header.append(
"\n");
7187 if(
true != headerOK)
7189 SC(
"Do not use non-ASCII for the translation of this item")
7190 fl_message_title(S("Error"));
7191 fl_alert("%s", S("Creating message header failed"));
7195 const char* header_text;
7196 header_text = header.text();
7197 if(NULL != header_text)
7201 SC("Do not use characters for the translation that cannot be")
7202 SC("converted to the ISO 8859-1 character set for the items")
7203 SC("in this section.")
7204 SC("Leave the original strings in place if in doubt.")
7207 titleString << S(
"Compose followup or reply") << std::flush;
7209 else { titleString << S(
"Compose new article") << std::flush; }
7221 const std::
string& ts = titleString.str();
7224 #if CFG_USE_XSI && !CFG_NLS_DISABLE
7230 title = gui_utf8_iso(ts.c_str());
7234 composeWindow =
new ComposeWindow(title, header_text, cq,
from,
7240 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
7242 composeWindow =
new ComposeWindow(ts.c_str(), header_text, cq,
from,
7245 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
7247 std::free((
void*) header_text);
7252 if(NULL !=
from) {
delete[]
from; }
7253 std::free((
void*) p);
7258 if(!stateMachine(EVENT_COMPOSE_EXIT))
7260 PRINT_ERROR(
"Error in main window state machine");
7273 void MainWindow::articlePost(
int action,
const char* article)
7285 free_method = FM_DEFAULT;
7286 if(UI_CB_START == action)
7288 if(!stateMachine(EVENT_POST)) { rv = 1; }
7298 SC(
"Do not use non-ASCII for the translation of this item")
7299 fl_message_title(S("Error"));
7300 fl_alert("%s", S("Conversion
from local to canonical form failed"));
7307 std::free((
void*) article);
7309 free_method = FM_CORE;
7316 SC(
"Do not use non-ASCII for the translation of this item")
7317 fl_message_title(S("Error"));
7318 fl_alert("%s", S("External postprocessor failed"));
7325 if(FM_CORE == free_method) {
core_free((
void*) article); }
7326 else { std::free((
void*) article); }
7328 free_method = FM_EXT;
7350 std::free((
void*) article);
7367 if(!stateMachine(EVENT_POST_EXIT))
7369 PRINT_ERROR(
"Error in main window state machine");
7373 UI_STATUS(S(
"Posting article failed."));
7374 SC(
"Do not use non-ASCII for the translation of this item")
7375 fl_message_title(S("Error"));
7376 fl_alert("%s", S("Posting article failed."));
7381 UI_STATUS(S(
"Article successfully posted."));
7382 if(NULL != composeWindow)
7384 delete composeWindow;
7385 composeWindow = NULL;
7401 Fl_Tree_Item* MainWindow::searchSelectArticle(
const char* target_mid,
7410 ti = articleTree->root();
7412 while(NULL != (ti = articleTree->next(ti)))
7415 if(std::strlen(mid) != tlen + (std::size_t) 2)
7420 if(!std::strncmp(&mid[1], target_mid, tlen))
7424 while(articleTree->root() != oi)
7426 if(!articleTree->open(oi))
7428 articleTree->open(oi, 1);
7430 for(i = 0; i < articleTree->root()->children(); ++i)
7432 if(articleTree->root()->child(i) == oi)
7438 if(abort) {
break; }
7439 oi = articleTree->prev(oi);
7442 articleTree->set_item_focus(ti);
7443 articleTree->deselect_all();
7444 articleTree->select(ti, 1);
7445 Fl::focus(articleTree);
7457 void MainWindow::storeMIMEEntityToFile(
const char* uri,
const char*
msgid)
7459 const char* link = NULL;
7460 const char* start = NULL;
7461 std::size_t len = 0;
7466 const char* suggest = NULL;
7469 link = gui_create_link_to_entity(
msgid, 0);
7470 if(NULL != link && link[0])
7474 p = std::strrchr(start, (
int)
'/');
7477 len = (size_t) (p - start);
7485 fprintf(stderr,
"%s: %sCannot check link to MIME entity (bug)\n",
7490 fprintf(stderr,
"%s: %sClick on link to MIME entity detected:\n",
7494 for(i = 0; len > (std::size_t) i; ++i)
7496 fprintf(stderr,
"%c", start[i]);
7498 fprintf(stderr,
" (Compare, Length: %u)\n", (
unsigned int) len);
7502 if(error || std::strncmp(uri, start, len))
7505 SC(
"Do not use non-ASCII for the translation of this item")
7506 fl_message_title(S("Error"));
7507 fl_alert("%s", S("Link target not found or not supported"));
7512 p = std::strrchr(uri, (
int)
'/');
7513 if(NULL == p || 1 != std::sscanf(++p,
"%u", &i))
7515 PRINT_ERROR(
"Extracting MIME entity number from file URI failed");
7520 const char* entity_body = mimeData->part(i, &cte, NULL);
7521 if(NULL != entity_body)
7523 SC(
"Do not use characters for the translation that cannot be")
7524 SC("converted to the ISO 8859-1 character set for this item.")
7525 SC("Leave the original
string in place if in doubt.")
7526 const
char* title = S("Save attachment");
7530 if(NULL != mimeData->filename(i))
7533 name = (
char*) std::malloc(std::strlen(homedir)
7534 + std::strlen(mimeData->filename(i))
7539 std::strcpy(name, homedir);
7540 std::strcat(name,
"/");
7541 std::strcat(name, mimeData->filename(i));
7549 if (NULL != suggest)
7551 fl_file_chooser_ok_label(S(
"Save"));
7552 const char* pathname =
7553 fl_file_chooser(title,
"*", suggest, 0);
7554 if(NULL != pathname)
7561 SC(
"Do not use non-ASCII for the translation of this item")
7562 fl_message_title(S("Error"));
7564 S("Pathname conversion to locale codeset failed"));
7572 SC(
"Do not use non-ASCII for the translation of this item")
7573 fl_message_title(S("Error"));
7574 fl_alert("%s", S("Operation failed"));
7585 std::free((
void*) link);
7586 std::free((
void*) suggest);
7593 void MainWindow::hyperlinkHandler(
int pos)
7595 const char* mailto =
"mailto:";
7596 const char* news =
"news:";
7597 const char* nntp =
"nntp:";
7598 const char* file =
"file:";
7615 if(currentArticle && currentStyle)
7620 i = currentArticle->prev_char(i);
7621 if(currentStyle->char_at(i) == hyperlinkStyle) { start = i; }
7627 i = currentArticle->next_char(i);
7628 if(currentStyle->char_at(i) == hyperlinkStyle) { end = i; }
7629 else { ++end;
break; }
7631 uri = currentArticle->text_range(start, end);
7635 len = std::strlen(nntp);
7636 if(std::strlen(uri) >= len && !std::strncmp(uri, nntp, len))
7639 PRINT_ERROR(
"Multi server support missing for nntp URI type");
7640 SC(
"Do not use non-ASCII for the translation of this item")
7641 fl_message_title(S("Error"));
7642 fl_alert("%s", S("URI type is not supported"));
7651 len = std::strlen(news);
7652 if(std::strlen(uri) >= len && !std::strncmp(uri, news, len))
7655 if(!std::strncmp(&uri[len],
"///", 3))
7657 std::memmove(&uri[len], &uri[len + (
size_t) 3],
7658 std::strlen(&uri[len + (
size_t) 3])
7661 if(std::strlen(uri) == len)
7663 SC(
"Do not use non-ASCII for the translation of this item")
7664 fl_message_title(S("Error"));
7665 fl_alert("%s", S("Invalid URI format"));
7668 else if(std::strchr(&uri[len], (
int) '/'))
7670 SC(
"Do not use non-ASCII for the translation of this item")
7671 fl_message_title(S("Error"));
7673 S("Server specification in URI not supported"));
7677 else if(!std::strchr(&uri[len], (
int) '@'))
7680 if(std::strchr(&uri[len], (
int)
'*')
7681 || std::strchr(&uri[len], (
int)
'?'))
7683 SC(
"Do not use non-ASCII for the translation of this item")
7684 fl_message_title(S("Error"));
7685 fl_alert("%s", S("URI doesn't specify a single group"));
7692 SC(
"Do not use non-ASCII for the translation of this item")
7693 fl_message_title(S("Error"));
7694 fl_alert("%s", S("Invalid URI format"));
7701 for(gi = 0; gi < group_num; ++gi)
7703 clen = std::strlen(&uri[len]);
7704 if(std::strlen(group_list[gi].name) == clen)
7706 if(!strncmp(&uri[len], group_list[gi].name,
7709 if((std::size_t) INT_MAX >= ++gi)
7711 groupList->select((
int) gi);
7712 groupSelect(UI_CB_START, (
int) gi);
7723 fl_message_title(S(
"Note"));
7724 rv = fl_choice(
"%s", S(
"No"),
7727 S(
"URI specifies a group that is not subscribed.\nSubscribe now?"));
7730 rv = groupStateMerge();
7736 UI_STATUS(S(
"Group subscription stored."));
7739 if(NULL != mainWindow)
7742 mainWindow->groupListImport();
7748 S(
"Click URI again after operation is complete"));
7761 SC(
"Do not use non-ASCII for the translation of this item")
7762 fl_message_title(S("Error"));
7763 fl_alert("%s", S("Invalid URI format"));
7767 clen = std::strlen(&uri[len]);
7768 ti = searchSelectArticle(&uri[len], clen);
7776 viewArticle(UI_CB_START, (
const char*) &uri[len]);
7784 clen = std::strlen(uri);
7785 if(std::strspn(uri,
"0123456789") == clen)
7788 if((std::size_t) INT_MAX >= clen && (std::size_t) 20 >= clen)
7793 p = currentArticleHE->header->refs[ref_i];
7794 clen = std::strlen(p);
7796 std::strncpy(q, &p[1], clen - (std::size_t) 2);
7797 q[clen - (std::size_t) 2] = 0;
7798 viewArticle(UI_CB_START, q);
7806 len = std::strlen(mailto);
7807 if(std::strlen(uri) >= len && !std::strncmp(uri, mailto, len))
7809 if(std::strlen(uri) == len)
7811 SC(
"Do not use non-ASCII for the translation of this item")
7812 fl_message_title(S("Error"));
7813 fl_alert("%s", S("Invalid URI format"));
7828 len = std::strlen(file);
7829 if(std::strlen(uri) >= len
7830 && !std::strncmp(uri, file, len))
7832 if(std::strlen(uri) == len)
7834 SC(
"Do not use non-ASCII for the translation of this item")
7835 fl_message_title(S("Error"));
7836 fl_alert("%s", S("Invalid URI format"));
7841 storeMIMEEntityToFile(uri,
7842 currentArticleHE->header->msgid);
7850 if(0 > rv && invalid)
7852 SC(
"Do not use non-ASCII for the translation of this item")
7853 fl_message_title(S("Error"));
7854 fl_alert("%s", S("Invalid characters in URI"));
7858 SC(
"Do not use non-ASCII for the translation of this item")
7859 fl_message_title(S("Error"));
7860 fl_alert("%s", S("Starting external URI handler failed"));
7869 std::free((
void*) uri);
7882 MainWindow::MainWindow(const
char* label) :
7883 UI_WINDOW_CLASS(730, 395, label)
7885 const char* enabled = S(
"Enabled");
7886 const char* disabled = S(
"Disabled");
7887 const char* available = S(
"Available");
7888 const char* notavailable = S(
"Not available");
7897 FL_FOREGROUND_COLOR,
7903 FL_FOREGROUND_COLOR,
7909 Fl_Group* mainGroup;
7910 Fl_Group* statusGroup;
7915 mainState = STATE_READY;
7919 wrapMode = Fl_Text_Display::WRAP_NONE;
7921 hyperlinkPosition = -1;
7927 group_list_index = 0;
7930 subscribedGroups = NULL;
7931 currentGroup = NULL;
7932 currentArticle = NULL;
7933 currentStyle = NULL;
7934 lastArticleHE = NULL;
7935 currentArticleHE = NULL;
7939 p =
new char[1]; p[0] = 0;
7940 currentSearchString = p;
7941 currentSearchPosition = 0;
7944 progress_skip_update =
false;
7950 subscribeWindow = NULL;
7953 composeWindow = NULL;
7954 composeWindowLock = 0;
7957 callback(exit_cb, (
void*)
this);
7960 aboutString << enabled << disabled << available << notavailable;
7961 aboutString.str(std::string());
7962 aboutString.clear();
7965 aboutString << CFG_NAME <<
" " << CFG_VERSION
7966 <<
" " << S(
"for") <<
" " << CFG_OS <<
"\n"
7967 #if defined(CFG_MODIFIED) && CFG_MODIFIED != 0
7969 <<
"(This is a modified version!)" <<
"\n"
7970 #endif // CFG_MODIFIED
7972 << S(
"Unicode version") <<
": " << UC_VERSION <<
"\n"
7975 #if CFG_USE_XSI && !CFG_NLS_DISABLE
7976 << S(
"Enabled") <<
"\n"
7977 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
7978 << S(
"Disabled") <<
"\n"
7979 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
7983 << S(
"Available") <<
"\n"
7984 << S(
"Required OpenSSL ABI") <<
": "
7985 # if CFG_USE_LIBRESSL
7986 <<
"LibreSSL" <<
"\n"
7987 # else // CFG_USE_LIBRESSL
7988 # if !CFG_USE_OPENSSL_API_3 && !CFG_USE_OPENSSL_API_1_1
7990 # else // !CFG_USE_OPENSSL_API_3 && !CFG_USE_OPENSSL_API_1_1
7991 # if !CFG_USE_OPENSSL_API_3
7993 # else // !CFG_USE_OPENSSL_API_3
7995 # endif // !CFG_USE_OPENSSL_API_3
7996 # endif // !CFG_USE_OPENSSL_API_3 && !CFG_USE_OPENSSL_API_1_1
7997 # endif // CFG_USE_LIBRESSL
7998 #else // CFG_USE_TLS
7999 << S(
"Not available") <<
"\n"
8000 #endif // CFG_USE_TLS
8002 << S(
"Required FLTK ABI") <<
": " << FL_MAJOR_VERSION <<
"."
8004 #ifdef FL_ABI_VERSION
8005 <<
"." << FL_ABI_VERSION % 100
8006 #else // FL_ABI_VERSION
8008 #endif // FL_ABI_VERSION
8011 << S(
"FLTK Double Buffering: ")
8013 << S(
"Disabled") <<
"\n"
8014 #else // CFG_DB_DISABLE
8015 << S(
"Enabled") <<
"\n"
8016 #endif // CFG_DB_DISABLE
8018 << S(
"Compression: ")
8019 #if CFG_CMPR_DISABLE
8020 << S(
"Disabled") <<
"\n"
8021 #else // CFG_CMPR_DISABLE
8025 # endif // CFG_USE_ZLIB
8027 #endif // CFG_CMPR_DISABLE
8029 <<
"Build: " << BDATE << std::flush;
8038 mainGroup =
new Fl_Group(0, 0, 730, 395);
8042 #if CFG_COCOA_SYS_MENUBAR
8043 menu =
new Fl_Sys_Menu_Bar(0, 0, 730, 0);
8044 #else // CFG_COCOA_SYS_MENUBAR
8045 menu =
new Fl_Menu_Bar(0, 0, 730, 30);
8046 #endif // CFG_COCOA_SYS_MENUBAR
8047 menu->selection_color(UI_COLOR_MENU_SELECTION);
8048 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
8050 menu->box(FL_THIN_UP_BOX);
8051 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
8052 menu->box(FL_FLAT_BOX);
8053 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
8056 SC("This section is for the
main window menubar and pull-down menus.")
8057 SC("The 2 spaces after every
string are intended and must be preserved.")
8058 SC("The part before the slash is the menubar entry and must be unique.")
8059 SC("The character after & is the key to pull-down a menu with 'Alt-key'.")
8060 SC("You can assign the & to any character before the slash,")
8061 SC("provided again that it is unique in the menubar!")
8062 SC("The part behind the slash is the name of the pull-down menu entry,")
8063 SC("it must only be unique inside the corresponding pull-down menu.")
8064 SC("If the name contains a slash, a submenu is created.")
8066 SC("It is not possible to localize the keyboard shortcuts for the")
8067 SC("pull-down menu entries. It was implemented this way for easier")
8068 SC("documentation and for the possibility to execute blind keyboard")
8069 SC("commands in the case of a misconfigured locale.")
8070 menu->add(S("&File/Save article "), 0, asave_cb, (
void*) this);
8071 menu->add(S("&File/Print article "), 0, print_cb, (
void*) this);
8072 menu->add(S("&File/Quit "), "^q", exit_cb, (
void*) this);
8074 menu->add(S("&Edit/Server "), 0, server_cb, (
void*) this);
8075 menu->add(S("&Edit/Configuration "), 0, config_cb, (
void*) this);
8076 menu->add(S("&Edit/Identity "), 0, identity_cb, (
void*) this);
8080 menu->add(S(
"&Group/Threaded view "),
"^t", thrv_cb, (
void*)
this, i);
8084 menu->add(S(
"&Group/Sort by article number "), 0, uthrv_sort_cb,
8088 menu->add(S(
"&Group/Show only unread articles "), 0, onlyur_cb,
8090 menu->add(S(
"&Group/Subscribe "), 0, gsubscribe_cb, (
void*)
this);
8091 menu->add(S(
"&Group/Unsubscribe "), 0, gunsubscribe_cb, (
void*)
this);
8092 menu->add(S(
"&Group/Sort list "), 0, gsort_cb, (
void*)
this);
8093 menu->add(S(
"&Group/Refresh list "),
"^r", grefresh_cb, (
void*)
this);
8094 menu->add(S(
"&Group/Next unread group "),
"^g", nug_cb, (
void*)
this);
8095 menu->add(S(
"&Group/Mark subthread read "), 0, mssar_cb,
8097 menu->add(S(
"&Group/Mark all in group read "),
"^a", maar_cb,
8099 menu->add(S(
"&Group/Mark all groups read "), 0, magar_cb,
8102 menu->add(S(
"&Article/Search in article "),
"/", asearch_cb, (
void*)
this);
8103 menu->add(S(
"&Article/Post to newsgroup "),
"^p", compose_cb,
8105 menu->add(S(
"&Article/Followup to newsgroup "),
"^f", reply_cb,
8107 menu->add(S(
"&Article/Supersede in newsgroup "), 0, supersede_cb,
8109 menu->add(S(
"&Article/Cancel in newsgroup "), 0, cancel_cb,
8111 menu->add(S(
"&Article/Reply by e-mail "),
"^m", email_cb, (
void*)
this);
8112 menu->add(S(
"&Article/Wrap to width "),
"^w", wrap_cb, (
void*)
this);
8113 menu->add(S(
"&Article/ROT13 "),
"^o", rot13_cb, (
void*)
this);
8114 menu->add(S(
"&Article/Next unread article "),
"^n", nua_cb,
8116 menu->add(S(
"&Article/Previous read article "),
"^b", pra_cb,
8118 menu->add(S(
"&Article/View source "),
"^e", viewsrc_cb, (
void*)
this);
8119 menu->add(S(
"&Article/Toggle read unread "),
"^u", msau_cb,
8124 menu->add(S(
"&Tools/Protocol console "), 0, console_cb, (
void*)
this);
8125 menu->add(S(
"&Tools/Search Message-ID "),
"^s", mid_search_cb,
8128 menu->add(S(
"&Help/About "), 0, about_cb, (
void*)
this);
8129 menu->add(S(
"&Help/Message of the day "), 0, viewmotd_cb, (
void*)
this);
8130 menu->add(S(
"&Help/License "), 0, license_cb, (
void*)
this);
8131 menu->add(S(
"&Help/Bug report "), 0, bug_cb, (
void*)
this);
8136 #if CFG_COCOA_SYS_MENUBAR
8137 contentGroup =
new Fl_Tile(0, 0, 730, 370);
8138 #else // CFG_COCOA_SYS_MENUBAR
8139 contentGroup =
new Fl_Tile(0, 30, 730, 340);
8140 #endif // CFG_COCOA_SYS_MENUBAR
8141 contentGroup->begin();
8144 #if CFG_COCOA_SYS_MENUBAR
8145 groupList =
new Fl_Hold_Browser(0, 0, 230, 370);
8146 #else // CFG_COCOA_SYS_MENUBAR
8147 groupList =
new Fl_Hold_Browser(0, 30, 230, 340);
8148 #endif // CFG_COCOA_SYS_MENUBAR
8149 groupList->callback(gselect_cb, (
void*)
this);
8150 #if CFG_COCOA_SYS_MENUBAR
8151 contentGroup2 =
new Fl_Tile(230, 0, 500, 370);
8152 #else // CFG_COCOA_SYS_MENUBAR
8153 contentGroup2 =
new Fl_Tile(230, 30, 500, 340);
8154 #endif // CFG_COCOA_SYS_MENUBAR
8155 contentGroup2->begin();
8158 #if CFG_COCOA_SYS_MENUBAR
8159 articleTree =
new My_Tree(230, 0, 500, 140);
8160 #else // CFG_COCOA_SYS_MENUBAR
8161 articleTree =
new My_Tree(230, 30, 500, 140);
8162 #endif // CFG_COCOA_SYS_MENUBAR
8163 articleTree->showroot(0);
8164 articleTree->connectorstyle(FL_TREE_CONNECTOR_SOLID);
8165 articleTree->connectorcolor(FL_FOREGROUND_COLOR);
8168 articleTree->item_labelfgcolor(FL_FOREGROUND_COLOR);
8169 ti = articleTree->add(S(
"No articles"));
8170 if(NULL != ti) { ti->deactivate(); }
8171 articleTree->callback(aselect_cb, (
void*)
this);
8173 #if CFG_COCOA_SYS_MENUBAR
8174 text =
new My_Text_Display(230, 140, 500, 230);
8175 #else // CFG_COCOA_SYS_MENUBAR
8176 text =
new My_Text_Display(230, 170, 500, 200);
8177 #endif // CFG_COCOA_SYS_MENUBAR
8178 text->callback(hyperlink_cb, (
void*)
this);
8179 text->textfont(FL_COURIER);
8181 contentGroup2->end();
8183 contentGroup->end();
8186 statusGroup =
new Fl_Group(0, 370, 730, 25);
8187 statusGroup->begin();
8190 progressBar =
new Fl_Progress(0, 370, 100, 25);
8192 progressBar->minimum(0.0);
8193 progressBar->maximum(100.0);
8194 progressBar->value(0.0);
8195 progressBar->label(
"");
8197 statusBar =
new Fl_Box(100, 370, 730, 25);
8198 statusBar->box(FL_DOWN_BOX);
8199 statusBar->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
8200 statusBar->label(
"");
8203 statusGroup->resizable(statusBar);
8206 mainGroup->resizable(contentGroup);
8213 styles =
new Fl_Text_Display::Style_Table_Entry[styles_len];
8214 styles[0].color = FL_FOREGROUND_COLOR;
8215 styles[0].font = FL_COURIER_BOLD;
8216 styles[0].size = text->textsize();
8218 for(i = 1; i < styles_len; ++i)
8220 styles[i].color = styles_colors[i];
8221 styles[i].font = text->textfont();
8222 styles[i].size = text->textsize();
8240 MainWindow::~MainWindow(
void)
8242 if(NULL != subscribedGroups)
8246 if(NULL != mimeData) {
delete mimeData; }
8247 delete[] currentSearchString;
8251 text->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
8252 if(currentStyle) {
delete currentStyle; }
8255 text->buffer(dummyTb);
8256 if(currentArticle) {
delete currentArticle; }
8263 int ServerCfgWindow::process(
void)
8266 while(!finished) { Fl::wait(); }
8269 sconf->serverReplace(scfgHostname->value());
8270 sconf->serviceReplace(scfgService->value());
8271 if(scfgTlsStrong->value()) { sconf->enc = UI_ENC_STRONG; }
8272 else if(scfgTlsWeak->value()) { sconf->enc = UI_ENC_WEAK; }
8273 else { sconf->enc = UI_ENC_NONE; }
8274 if(scfgAuthUser->value()) { sconf->auth = UI_AUTH_USER; }
8275 else { sconf->auth = UI_AUTH_NONE; }
8284 ServerCfgWindow::ServerCfgWindow(ServerConfig* sc,
const char* label) :
8285 UI_WINDOW_CLASS(700, 395, label)
8290 int y, w, h, gy, gh, bw;
8292 std::ostringstream serverString;
8293 std::ostringstream serviceString;
8294 std::ostringstream tlsString;
8302 callback(cancel_cb, (
void*)
this);
8305 serverString << S(
"NNTP server hostname")
8306 <<
" (" << S(
"or IP address") <<
")" << std::flush;
8308 serviceString << S(
"Service name")
8309 <<
" (" << S(
"or TCP port") <<
")" << std::flush;
8310 tlsString <<
"Transport Layer Security (TLS)"
8311 <<
" " << S(
"and server to client authentication") << std::flush;
8323 const std::string& srv_s = serverString.str();
8324 const std::string& svc_s = serviceString.str();
8325 const std::string& tls_s = tlsString.str();
8328 hostname =
new char[std::strlen(srv_s.c_str()) + (std::size_t) 1];
8329 std::strcpy(hostname, srv_s.c_str());
8330 service =
new char[std::strlen(svc_s.c_str()) + (std::size_t) 1];
8331 std::strcpy(service, svc_s.c_str());
8332 tls_headline =
new char[std::strlen(tls_s.c_str()) + (std::size_t) 1];
8333 std::strcpy(tls_headline, tls_s.c_str());
8336 scfgGroup =
new Fl_Group(0, 0, 700, 395);
8340 gui_set_default_font();
8341 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
8342 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
8343 if(w1 > w2) { w = w1; }
else { w = w2; }
8344 if(h1 > h2) { h = h1; }
else { h = h2; }
8350 scfgHostname =
new Fl_Input(15, 35, 450, 30, hostname);
8351 scfgHostname->align(FL_ALIGN_TOP_LEFT);
8352 scfgHostname->value(sc->server);
8354 scfgService =
new Fl_Input(480, 35, 205, 30, service);
8355 scfgService->align(FL_ALIGN_TOP_LEFT);
8356 scfgService->value(sc->service);
8358 grpTls =
new Fl_Group(15, 100, 670, 120, tls_headline);
8361 scfgTlsOff =
new Fl_Radio_Round_Button(30, 115, 640, 30,
8364 scfgTlsOff->callback(enc_off_cb, (
void*)
this);
8365 scfgTlsStrong =
new Fl_Radio_Round_Button(30, 145, 640, 30,
8366 S(
"Enabled with strong encryption and forward secrecy"));
8368 scfgTlsStrong->callback(enc_on_cb, (
void*)
this);
8369 scfgTlsWeak =
new Fl_Radio_Round_Button(30, 175, 640, 30,
8370 S(
"Enabled in compatibility mode offering weak cipher suites"));
8372 scfgTlsWeak->callback(enc_on_cb, (
void*)
this);
8375 grpTls->align(FL_ALIGN_TOP_LEFT);
8376 grpTls->box(FL_EMBOSSED_BOX);
8378 grpTls->deactivate();
8379 sc->enc = UI_ENC_NONE;
8380 #endif // CFG_USE_TLS
8383 case UI_ENC_STRONG: { scfgTlsStrong->set();
break; }
8384 case UI_ENC_WEAK: { scfgTlsWeak->set();
break; }
8385 default: { scfgTlsOff->set();
break; }
8388 grpAuth =
new Fl_Group(15, 255, 670, 90,
8389 S(
"Client to server authentication"));
8392 scfgAuthOff =
new Fl_Radio_Round_Button(30, 270, 640, 30,
8395 scfgAuthUser =
new Fl_Radio_Round_Button(30, 300, 640, 30,
8396 S(
"AUTHINFO USER/PASS as defined in RFC 4643"));
8400 grpAuth->align(FL_ALIGN_TOP_LEFT);
8401 grpAuth->box(FL_EMBOSSED_BOX);
8402 #if !CFG_NNTP_AUTH_UNENCRYPTED
8403 if(UI_ENC_NONE == sc->enc)
8406 grpAuth->deactivate();
8413 case UI_AUTH_USER: { scfgAuthUser->set();
break; }
8414 default: { scfgAuthOff->set();
break; }
8418 gp =
new Fl_Group(0, gy, 700, gh);
8423 new Fl_Box(0, gy, bw, gh);
8424 p =
new Fl_Button(15, y, w, h, S(
"OK"));
8425 p->callback(ok_cb, (
void*)
this);
8426 new Fl_Box(500 - bw, gy, bw, gh);
8427 p =
new Fl_Button(700 - bw + 15, y, w, h, S(
"Cancel"));
8428 p->callback(cancel_cb, (
void*)
this);
8430 bp =
new Fl_Box(bw, gy, 700 - (2 * bw), gh);
8436 resizable(scfgGroup);
8438 size_range(700, 395, 700, 395);
8440 Fl::visual(FL_DOUBLE | FL_INDEX);
8441 #endif // CFG_DB_DISABLE
8449 ServerCfgWindow::~ServerCfgWindow(
void)
8453 delete[] tls_headline;
8462 void IdentityCfgWindow::ok_cb_i(
void)
8469 len1 = std::strlen(fromName->value());
8470 len2 = std::strlen(fromEmail->value());
8473 SC(
"Do not use non-ASCII for the translation of this item")
8474 fl_message_title(S("Error"));
8475 fl_alert("%s", S("From header field element too
long"));
8477 buf = new
char[len1 + len2 + (std::
size_t) 4];
8481 if(len1) { std::strcat(buf, fromName->value()); }
8482 std::strcat(buf,
" <");
8483 std::strcat(buf, fromEmail->value());
8484 std::strcat(buf,
">");
8490 len1 = std::strlen(replytoName->value());
8491 len2 = std::strlen(replytoEmail->value());
8494 SC(
"Do not use non-ASCII for the translation of this item")
8495 fl_message_title(S("Error"));
8496 fl_alert("%s", S("Reply-To header field element too
long"));
8498 buf = new
char[len1 + len2 + (std::
size_t) 4];
8502 if(len1) { std::strcat(buf, replytoName->value()); }
8503 std::strcat(buf,
" <");
8504 std::strcat(buf, replytoEmail->value());
8505 std::strcat(buf,
">");
8515 Fl::delete_widget(
this);
8522 IdentityCfgWindow::IdentityCfgWindow(
const char* label) :
8523 UI_WINDOW_CLASS(700, 200, label)
8534 int y, w, h, gy, gh, bw;
8540 callback(cancel_cb, (
void*)
this);
8546 if(std::strlen(from_name))
8551 if(
'<' == from_name[i])
8554 if(NULL == std::strchr(&from_name[i + (std::size_t) 1], (
int)
'<'))
8557 if(!i || ((std::size_t) 1 == i &&
' ' == from_name[0]))
8561 else { from_name[i - (std::size_t) 1] = 0; }
8563 i = std::strlen(from_email) - (std::size_t) 1;
8564 if(
'>' != from_email[i]) { from_email[0] = 0; }
8565 else { from_email[i] = 0; }
8574 replyto_email[0] = 0;
8575 if(std::strlen(replyto_name))
8578 while(replyto_name[i])
8580 if(
'<' == replyto_name[i])
8582 if(!i || ((std::size_t) 1 == i &&
' ' == replyto_name[0]))
8584 replyto_name[0] = 0;
8586 else { replyto_name[i - (std::size_t) 1] = 0; }
8588 i = std::strlen(replyto_email) - (std::size_t) 1;
8589 if(
'>' != replyto_email[i]) { replyto_email[0] = 0; }
8590 else { replyto_email[i] = 0; }
8598 cfgGroup =
new Fl_Group(0, 0, 700, 200);
8602 gui_set_default_font();
8603 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
8604 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
8605 if(w1 > w2) { w = w1; }
else { w = w2; }
8606 if(h1 > h2) { h = h1; }
else { h = h2; }
8612 gp1 =
new Fl_Group(0, 0, 700, gy);
8616 fromName =
new Fl_Input(15, 35, 325, 30,
"From (Name):");
8617 fromName->align(FL_ALIGN_TOP_LEFT);
8618 fromName->value(from_name);
8620 fromEmail =
new Fl_Input(355, 35, 325, 30,
"From (e-mail):");
8621 fromEmail->align(FL_ALIGN_TOP_LEFT);
8622 fromEmail->value(from_email);
8624 replytoName =
new Fl_Input(15, 100, 325, 30,
"Reply-To (Name):");
8625 replytoName->align(FL_ALIGN_TOP_LEFT);
8626 replytoName->value(replyto_name);
8628 replytoEmail =
new Fl_Input(355, 100, 325, 30,
"Reply-To (e-mail):");
8629 replytoEmail->align(FL_ALIGN_TOP_LEFT);
8630 replytoEmail->value(replyto_email);
8632 bp =
new Fl_Box(0, 150, 700, gy - 150);
8638 gp2 =
new Fl_Group(0, gy, 700, gh);
8643 new Fl_Box(0, gy, bw, gh);
8644 p =
new Fl_Button(15, y, w, h, S(
"OK"));
8645 p->callback(ok_cb, (
void*)
this);
8646 new Fl_Box(500 - bw, gy, bw, gh);
8647 p =
new Fl_Button(700 - bw + 15, y, w, h, S(
"Cancel"));
8648 p->callback(cancel_cb, (
void*)
this);
8650 bp =
new Fl_Box(bw, gy, 700 - (2 * bw), gh);
8656 cfgGroup->resizable(gp1);
8657 resizable(cfgGroup);
8659 size_range(700, 150 + gh, 0, 0);
8661 Fl::visual(FL_DOUBLE | FL_INDEX);
8662 #endif // CFG_DB_DISABLE
8670 IdentityCfgWindow::~IdentityCfgWindow(
void)
8678 void MiscCfgWindow::ok_cb_i(
void)
8681 const unsigned int cac_limit = (
unsigned int) UI_CAC_MAX;
8686 is = cacField->value();
8687 if(NULL != is && 1 == std::sscanf(is,
"%u", &i))
8689 if(cac_limit < i) { i = cac_limit; }
8695 SC(
"Do not use non-ASCII for the translation of this item")
8696 fl_message_title(S("Error"));
8697 fl_alert("%s", S("Invalid value for CAC"));
8717 if(!error) { Fl::delete_widget(
this); }
8724 MiscCfgWindow::MiscCfgWindow(
const char* label) :
8725 UI_WINDOW_CLASS(400, 235, label)
8733 int y, w, h, gy, gh, bw;
8735 std::ostringstream ss;
8737 SC(
"Preserve the spaces at beginning and end")
8738 const
char* label_tab_cac = S(" Misc ");
8739 const
char* label_tab_qs = S(" Quote style ");
8740 SC("Preserve the colon")
8741 const
char* label_cac = S("Clamp article count threshold:");
8746 callback(cancel_cb, (
void*) this);
8749 gp1 = new Fl_Group(0, 0, 400, 235);
8753 gui_set_default_font();
8754 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
8755 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
8756 if(w1 > w2) { w = w1; }
else { w = w2; }
8757 if(h1 > h2) { h = h1; }
else { h = h2; }
8763 cfgTabs =
new Fl_Tabs(0, 0, 400, gy);
8766 cacGroup =
new Fl_Group(0, th - tg, 400, 235 - th + tg, label_tab_cac);
8769 cacField =
new Fl_Input(15, 55, 400 - 30, 30, label_cac);
8770 cacField->align(FL_ALIGN_TOP_LEFT);
8773 const std::string& s = ss.str();
8774 cacField->value(s.c_str());
8775 cmprEnable =
new Fl_Check_Button(15, 90, 400 - 30, 30,
8776 S(
"Negotiate compression if available"));
8777 cmprEnable->tooltip(
8778 SC(
"This is the tooltip for the compression negotiation checkbox")
8779 S(
"Not recommended when confidential newsgroups are accessed")
8782 #if CFG_CMPR_DISABLE
8783 cmprEnable->deactivate();
8784 #endif // CFG_CMPR_DISABLE
8785 localTime =
new Fl_Check_Button(15, 120, 400 - 30, 30,
8786 S(
"Use localtime for Date header field"));
8788 SC(
"This is the tooltip for the use localtime checkbox")
8789 S(
"Using localtime is recommended by RFC 5322")
8792 uagentEnable =
new Fl_Check_Button(15, 150, 400 - 30, 30,
8793 S(
"Add User-Agent header field"));
8796 bp =
new Fl_Box(0, 180, 400, gy - 150);
8800 cacGroup->resizable(bp);
8804 qsGroup =
new Fl_Group(0, th - tg, 400, 235 - th + tg, label_tab_qs);
8807 qsSpace =
new Fl_Check_Button(15, 45, 400 - 30, 30,
8808 S(
"Space after quote marks"));
8810 qsUnify =
new Fl_Check_Button(15, 75, 400 - 30, 30,
8811 S(
"Unify quote marks for follow-up"));
8814 bp =
new Fl_Box(0, 150, 400, gy - 150);
8818 qsGroup->resizable(bp);
8821 cfgTabs->resizable(cacGroup);
8823 gp2 =
new Fl_Group(0, gy, 400, gh);
8828 new Fl_Box(0, gy, bw, gh);
8829 p =
new Fl_Button(15, y, w, h, S(
"OK"));
8830 p->callback(ok_cb, (
void*)
this);
8831 new Fl_Box(500 - bw, gy, bw, gh);
8832 p =
new Fl_Button(400 - bw + 15, y, w, h, S(
"Cancel"));
8833 p->callback(cancel_cb, (
void*)
this);
8835 bp =
new Fl_Box(bw, gy, 400 - (2 * bw), gh);
8841 gp1->resizable(cfgTabs);
8844 size_range(400, 235, 0, 0);
8846 Fl::visual(FL_DOUBLE | FL_INDEX);
8847 #endif // CFG_DB_DISABLE
8855 MiscCfgWindow::~MiscCfgWindow(
void)
8863 void SearchWindow::ok_cb_i(
void)
8872 ss = searchField->value();
8878 SC(
"Do not use non-ASCII for the translation of this item")
8879 fl_message_title(S("Error"));
8880 fl_alert("%s", S("Processing Unicode
data in search
string failed"));
8884 if(std::strcmp(*currentSearchString, ss_nfc))
8887 tmp = std::strlen(ss_nfc);
8888 if((std::size_t) INT_MAX <= tmp) { len = INT_MAX - 1; }
8889 else { len = (int) tmp; }
8891 delete[] *currentSearchString;
8892 p =
new char[len + 1];
8893 std::strncpy(p, ss_nfc, (
size_t) len);
8895 *currentSearchString = p;
8898 if(ss != ss_nfc) {
enc_free((
void*) ss_nfc); }
8909 SearchWindow::SearchWindow(
const char* label,
const char** oldSearchString) :
8910 UI_WINDOW_CLASS(400, 165, label)
8913 Fl_Group* searchGroup;
8914 Fl_Group* searchGroup2;
8915 Fl_Group* buttonGroup;
8918 int y, w, h, gy, gh, bw;
8920 std::ostringstream ss;
8922 SC(
"Preserve the colon")
8923 const
char* label_search = S("Search for:");
8929 currentSearchString = oldSearchString;
8934 callback(cancel_cb, (
void*) this);
8937 gp = new Fl_Group(0, 0, 400, 165);
8941 gui_set_default_font();
8942 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
8943 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
8944 if(w1 > w2) { w = w1; }
else { w = w2; }
8945 if(h1 > h2) { h = h1; }
else { h = h2; }
8950 searchGroup =
new Fl_Group(0, 0, 400, 165 - gh);
8951 searchGroup->begin();
8954 searchGroup2 =
new Fl_Group(0, 0, 400, 80);
8955 searchGroup2->begin();
8958 searchField =
new Fl_Input(15, 35, 400 - 30, 30, label_search);
8959 searchField->align(FL_ALIGN_TOP_LEFT);
8961 ss << *currentSearchString << std::flush;
8962 const std::string& s = ss.str();
8963 searchField->value(s.c_str());
8965 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
8968 #else // defined FL_ABI_VERSION && 10303 <= FL_ABI_VERSION
8970 #endif // defined FL_ABI_VERSION && 10303 <= FL_ABI_VERSION
8971 (searchField->size(), 0);
8972 searchField->take_focus();
8974 searchGroup2->end();
8976 cisEnable =
new Fl_Check_Button(15, 80, 400 - 30, 30,
8977 S(
"Search case-insensitive"));
8979 cisEnable->clear_visible_focus();
8981 bp =
new Fl_Box(0, 110, 400, gy - 110);
8986 searchGroup->resizable(bp);
8988 buttonGroup =
new Fl_Group(0, gy, 400, gh);
8989 buttonGroup->begin();
8993 new Fl_Box(0, gy, bw, gh);
8994 p =
new Fl_Button(15, y, w, h, S(
"OK"));
8995 p->callback(ok_cb, (
void*)
this);
8996 p->shortcut(FL_Enter);
8997 p->clear_visible_focus();
8998 new Fl_Box(400 - bw, gy, bw, gh);
8999 p =
new Fl_Button(400 - bw + 15, y, w, h, S(
"Cancel"));
9000 p->callback(cancel_cb, (
void*)
this);
9001 p->shortcut(FL_Escape);
9002 p->clear_visible_focus();
9004 bp =
new Fl_Box(bw, gy, 400 - (2 * bw), gh);
9009 buttonGroup->resizable(bp);
9012 gp->resizable(searchGroup);
9015 size_range(400, 165, 0, 0);
9017 Fl::visual(FL_DOUBLE | FL_INDEX);
9018 #endif // CFG_DB_DISABLE
9026 SearchWindow::~SearchWindow(
void)
9040 const char* MIMEContent::createMessageHeader(
const char* message,
9043 const char* res = NULL;
9056 tb.append(
"[Invalid MIME message/rfc822 content]");
9062 tb.append(S(
"From"));
9064 tb.append(hdr->
from);
9068 tb.append(S(
"Subject"));
9074 tb.append(S(
"Date"));
9079 tb.append(
"[Missing or invalid header field]");
9088 tb.append(S(
"Message-ID"));
9093 tb.append(
"[Missing or invalid header field]");
9097 tb.append(hdr->
msgid);
9102 tb.append(S(
"Newsgroups"));
9106 if(!i && !hdr->
groups[0][0])
9109 tb.append(
"[Missing or invalid header field]");
9114 if(i) { tb.append(
","); }
9115 tb.append(hdr->
groups[i++]);
9125 std::free((
void*) p);
9139 MIMEContent::MIMEContentListElement*
9140 MIMEContent::decodeElement(
const char* p, std::size_t len,
char* boundary,
9141 bool alt,
bool digest, std::size_t* count)
9143 MIMEContentListElement* res = NULL;
9144 MIMEContentListElement* cle = NULL;
9145 MIMEContentListElement* ble = NULL;
9147 MIMEContentListElement* mle = NULL;
9149 MIMEContentListElement* lle = NULL;
9151 std::size_t bae = 0;
9152 std::size_t num = 0;
9160 bool message_rfc822;
9165 MIMEContentListElement* tmp;
9170 if(!std::strlen(boundary))
9172 PRINT_ERROR(
"vvv Extract MIME encapsulated message vvv");
9176 PRINT_ERROR(
"--- Split MIME multipart entity ---");
9178 fprintf(stderr,
"%s: %sSize of body: %lu octets\n",
9181 if(!std::strlen(boundary))
9189 for(i = 0; i < num; ++i)
9192 nested_multi =
false;
9194 nested_digest =
false;
9195 message_rfc822 =
false;
9202 PRINT_ERROR(
"Invalid entity in MIME multipart entity");
9225 message_rfc822 =
true;
9234 PRINT_ERROR(
"Content-Type: Text (using default)");
9238 PRINT_ERROR(
"Content-Type: Message (using default)");
9244 message_rfc822 =
false;
9247 if(ENC_CTE_UNKNOWN == cte)
9249 PRINT_ERROR(
"Unknown MIME Content-Transfer-Encoding");
9271 if(ENC_CS_UNKNOWN == ct.
charset)
9288 PRINT_ERROR(
"Content-Type: Image, Audio or Video");
9299 nested_multi =
true;
9306 nested_digest =
true;
9318 message_rfc822 =
true;
9352 && ENC_CTE_UNKNOWN != cte))
9364 cle = decodeElement(p, e_len,
9365 nested_boundary, nested_alt, nested_digest, &ae);
9368 else if(message_rfc822)
9371 nested_boundary[0] = 0;
9372 mle = decodeElement(p, e_len,
9373 nested_boundary, nested_alt, nested_digest, &ae);
9380 q = createMessageHeader(p, len);
9381 cle = initElement(q, std::strlen(q), cte, &ct, e_h);
9387 SC(
"Control characters for line break at the end must stay in place")
9388 q = S("End of encapsulated message.\r\n");
9389 mle = initElement(q, std::strlen(q), cte, &ct, e_h);
9393 while(NULL != tmp->next) { tmp = tmp->next; }
9399 cle = initElement(p, e_len, cte, &ct, e_h);
9404 PRINT_ERROR(
"Decoding MIME multipart message failed");
9417 if(!i) { res = cle; }
else { lle->next = cle; }
9420 while(NULL != lle->next) { lle = lle->next; }
9439 if(std::strlen(boundary))
9441 PRINT_ERROR(
"--- End of MIME multipart entity ---");
9445 PRINT_ERROR(
"^^^ End of MIME encapsulated message ^^^");
9456 MIMEContent::MIMEContentListElement*
9457 MIMEContent::initElement(
const char* body, std::size_t body_len,
9461 MIMEContentListElement* cle =
new MIMEContentListElement;
9464 bool headerPresent =
false;
9470 std::memcpy((
void*) &cle->ct, (
void*) ct,
sizeof(
enc_mime_ct));
9473 cp =
new char[body_len + (std::size_t) 1];
9474 std::strncpy(cp, body, body_len); cp[body_len] = 0;
9478 cle->type = ENC_CD_INLINE;
9479 cle->filename = NULL;
9482 if(NULL != hdr && NULL != hdr->
mime_cte)
9484 tb.append(S(
"Transfer-Encoding"));
9488 headerPresent =
true;
9490 if(NULL != hdr && NULL != hdr->
mime_ct)
9492 tb.append(S(
"Content-Type"));
9496 headerPresent =
true;
9498 if(NULL != hdr && NULL != hdr->
mime_cd)
9500 tb.append(S(
"Content-Disposition"));
9504 headerPresent =
true;
9510 cle->header = tb.text();
9542 "with missing MIME-Version header field");
9558 if(ENC_CTE_UNKNOWN == cte)
9577 if(ENC_CS_UNKNOWN == ct.
charset)
9621 partList = initElement(p, std::strlen(p), cte, &ct, h);
9628 partList = decodeElement(p, std::strlen(p),
9629 boundary, alt, digest, &partNum);
9637 MIMEContent::~MIMEContent(
void)
9639 MIMEContentListElement* cle = partList;
9640 MIMEContentListElement* nle;
9646 std::free((
void*) cle->header);
9647 delete[] cle->content;
9657 void SubscribeWindow::ok_cb_i(
void)
9659 Fl_Tree_Item* i = subscribeTree->first_selected_item();
9666 subscribeTree->showroot(0);
9669 mainWindow->groupStateExport();
9673 if(
'\0' != ((
const char*) i->user_data())[0])
9676 name = (
char*) i->user_data();
9682 rv = subscribeTree->item_pathname(buf, 1024, i);
9687 if(-2 == rv) {
PRINT_ERROR(
"Group name too long and ignored"); }
9694 {
if(
'/' == name[ii]) { name[ii] =
'.'; } }
9701 PRINT_ERROR(
"Updating list of subscribed groups failed");
9705 i = subscribeTree->next_selected_item(i);
9712 SC(
"Do not use non-ASCII for the translation of this item")
9713 fl_message_title(S("Error"));
9714 fl_alert("%s", S("Error while updating subscribed group database"));
9716 else {
UI_STATUS(S(
"Subscribed groups stored.")); }
9720 if(NULL != mainWindow)
9723 mainWindow->groupListImport();
9727 Fl::delete_widget(
this);
9734 SubscribeWindow::SubscribeWindow(
const char* label,
core_groupdesc* glist,
9736 UI_WINDOW_CLASS(730, 350, label), grouplist(glist), grouplabels(labels)
9741 int y, w, h, gy, gh, bw;
9746 callback(cancel_cb, (
void*)
this);
9753 subscribeGroup =
new Fl_Group(0, 0, 730, 350);
9754 subscribeGroup->begin();
9757 gui_set_default_font();
9758 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
9759 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
9760 if(w1 > w2) { w = w1; }
else { w = w2; }
9761 if(h1 > h2) { h = h1; }
else { h = h2; }
9767 subscribeTree =
new Fl_Tree(0, 0, 730, 350 - gh);
9770 subscribeTree->item_labelfgcolor(FL_FOREGROUND_COLOR);
9772 subscribeTree->root()->labelfgcolor(FL_FOREGROUND_COLOR);
9773 subscribeTree->root_label(
"Usenet");
9774 subscribeTree->margintop(5);
9775 subscribeTree->marginleft(0);
9776 subscribeTree->openchild_marginbottom(5);
9777 subscribeTree->selectmode(FL_TREE_SELECT_MULTI);
9778 subscribeTree->sortorder(FL_TREE_SORT_ASCENDING);
9779 subscribeTree->callback(tree_cb, (
void*)
this);
9781 gp =
new Fl_Group(0, gy, 730, gh);
9786 new Fl_Box(0, gy, bw, gh);
9787 p =
new Fl_Button(15, y, w, h, S(
"OK"));
9788 p->callback(ok_cb, (
void*)
this);
9789 new Fl_Box(730 - bw, gy, bw, gh);
9790 p =
new Fl_Button(730 - bw + 15, y, w, h, S(
"Cancel"));
9791 p->callback(cancel_cb, (
void*)
this);
9793 bp =
new Fl_Box(bw, gy, 730 - (2 * bw), gh);
9798 subscribeGroup->end();
9799 subscribeGroup->resizable(subscribeTree);
9800 resizable(subscribeGroup);
9806 size_range(2 * bw, 100, 0, 0);
9808 Fl::visual(FL_DOUBLE | FL_INDEX);
9809 #endif // CFG_DB_DISABLE
9817 SubscribeWindow::~SubscribeWindow(
void)
9827 void ProtocolConsole::update(
void)
9830 const char* logname;
9842 logfp = fopen(logname,
"r");
9843 log_free((
void*) logname); logname = NULL;
9847 protocolConsole->consoleDisplay->insert(
9848 S(
"Logfile is only available in debug mode.") );
9849 protocolConsole->consoleDisplay->insert(
"\n");
9850 protocolConsole->consoleDisplay->insert(
9851 S(
"Use command line option -debug for debug mode.") );
9859 for(n = 0; n <
sizeof(buffer) - 1; ++n)
9862 if(EOF == rv) {
break; }
9866 if(0x0D == rv) { buffer[n] = 0x20; }
9867 else { buffer[n] = (char) (
unsigned char) rv; }
9871 protocolConsole->consoleDisplay->insert(buffer);
9876 if(NULL == protocolConsole) {
break; }
9878 if(protocolConsole) { clearerr(logfp); }
9887 ProtocolConsole::ProtocolConsole(
const char* label) :
9888 UI_WINDOW_CLASS(730, 395, label), logfp(NULL), nolog(0)
9891 consoleText =
new Fl_Text_Buffer();
9892 consoleDisplay =
new Fl_Text_Display(0, 0, 730, 395);
9893 consoleDisplay->buffer(consoleText);
9894 resizable(consoleDisplay);
9895 callback(exit_cb, (
void*)
this);
9897 Fl::visual(FL_DOUBLE | FL_INDEX);
9898 #endif // CFG_DB_DISABLE
9906 ProtocolConsole::~ProtocolConsole(
void)
9908 if(logfp) { fclose(logfp); }
9911 delete consoleDisplay;
9914 protocolConsole = NULL;
9921 void MIDSearchWindow::ok_cb_i(
void)
9923 std::size_t limit = 248;
9924 const char* message_id = mid->value();
9930 len = std::strlen(message_id);
9931 buf =
new char[len + (std::size_t) 1];
9932 std::strcpy(buf, message_id);
9936 while(0x09 == (
int) p[0] ||
' ' == p[0] ||
'<' == p[0])
9941 while(0x09 == (
int) p[len - (std::size_t) 1]
9942 ||
' ' == p[len - (std::size_t) 1] ||
'>' == p[len - (std::size_t) 1])
9944 p[len - (std::size_t) 1] = 0;
9951 SC(
"Do not use non-ASCII for the translation of this item")
9952 fl_message_title(S("Error"));
9954 S("Message-ID too
long\nLimit is 250 characters, including angle brackets"));
9958 Fl::delete_widget(this);
9961 mainWindow->viewArticle(UI_CB_START, (const
char*) p);
9969 MIDSearchWindow::MIDSearchWindow(const
char* label) :
9970 UI_WINDOW_CLASS(700, 150, label)
9976 int y, w, h, gy, gh, bw;
9982 callback(cancel_cb, (
void*)
this);
9985 cfgGroup =
new Fl_Group(0, 0, 700, 150);
9989 gui_set_default_font();
9990 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
9991 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
9992 if(w1 > w2) { w = w1; }
else { w = w2; }
9993 if(h1 > h2) { h = h1; }
else { h = h2; }
9999 gp1 =
new Fl_Group(0, 0, 700, gy);
10003 mid =
new Fl_Input(15, 35, 670, 30,
"Message-ID:");
10004 mid->align(FL_ALIGN_TOP_LEFT);
10006 bp =
new Fl_Box(0, 100, 700, gy - 100);
10010 gp1->resizable(bp);
10012 gp2 =
new Fl_Group(0, gy, 700, gh);
10017 new Fl_Box(0, gy, bw, gh);
10018 p =
new Fl_Return_Button(15, y, w, h, S(
"OK"));
10019 p->callback(ok_cb, (
void*)
this);
10020 new Fl_Box(500 - bw, gy, bw, gh);
10021 p =
new Fl_Button(700 - bw + 15, y, w, h, S(
"Cancel"));
10022 p->callback(cancel_cb, (
void*)
this);
10023 p->shortcut(FL_Escape);
10026 bp =
new Fl_Box(bw, gy, 700 - (2 * bw), gh);
10029 gp2->resizable(bp);
10032 cfgGroup->resizable(gp1);
10033 resizable(cfgGroup);
10035 size_range(700, 100 + gh, 0, 0);
10036 #if !CFG_DB_DISABLE
10037 Fl::visual(FL_DOUBLE | FL_INDEX);
10038 #endif // CFG_DB_DISABLE
10046 MIDSearchWindow::~MIDSearchWindow(
void)
10054 BugreportWindow::BugreportWindow(
const char* label,
const char* content) :
10055 UI_WINDOW_CLASS(795, 395, label)
10060 len = std::strlen(content);
10061 if(INT_MAX < len) { len = 0; }
10062 bugreportText =
new Fl_Text_Buffer((
int) ++len, 0);
10063 bugreportText->insert(0, content);
10064 bugreportDisplay =
new Fl_Text_Display(0, 0, 795, 395);
10065 bugreportDisplay->textfont(FL_COURIER);
10066 bugreportDisplay->buffer(bugreportText);
10067 resizable(bugreportDisplay);
10068 callback(exit_cb, (
void*)
this);
10069 #if !CFG_DB_DISABLE
10070 Fl::visual(FL_DOUBLE | FL_INDEX);
10071 #endif // CFG_DB_DISABLE
10079 BugreportWindow::~BugreportWindow(
void)
10082 delete bugreportDisplay;
10083 delete bugreportText;
10090 MotdWindow::MotdWindow(
const char* motd,
const char* label) :
10091 UI_WINDOW_CLASS(795, 395, label)
10094 motdText =
new Fl_Text_Buffer();
10095 motdText->text(motd);
10096 motdDisplay =
new Fl_Text_Display(0, 0, 795, 395);
10097 motdDisplay->textfont(FL_COURIER);
10098 motdDisplay->buffer(motdText);
10099 resizable(motdDisplay);
10100 callback(exit_cb, (
void*)
this);
10101 #if !CFG_DB_DISABLE
10102 Fl::visual(FL_DOUBLE | FL_INDEX);
10103 #endif // CFG_DB_DISABLE
10111 MotdWindow::~MotdWindow(
void)
10114 delete motdDisplay;
10122 LicenseWindow::LicenseWindow(
const char* label) :
10123 UI_WINDOW_CLASS(795, 395, label)
10128 licenseText =
new Fl_Text_Buffer();
10129 rv = licenseText->loadfile(CFG_LICENSE_PATH
"/license.txt");
10130 if(rv) { licenseText->insert(0, S(
"Error: License file not found")); }
10131 licenseDisplay =
new Fl_Text_Display(0, 0, 795, 395);
10132 licenseDisplay->textfont(FL_COURIER);
10133 licenseDisplay->buffer(licenseText);
10134 resizable(licenseDisplay);
10135 callback(exit_cb, (
void*)
this);
10136 #if !CFG_DB_DISABLE
10137 Fl::visual(FL_DOUBLE | FL_INDEX);
10138 #endif // CFG_DB_DISABLE
10146 LicenseWindow::~LicenseWindow(
void)
10149 delete licenseDisplay;
10150 delete licenseText;
10159 return(gui_print_header_fields(h));
10166 void ArticleWindow::articleUpdate(Fl_Text_Buffer* article)
10169 const char* url[] = {
"http://",
"https://",
"ftp://",
"nntp://",
10170 "news:",
"mailto:", NULL };
10171 const std::size_t url_len[] = { 7, 8, 6, 7, 5, 7 };
10172 const char bold =
'A';
10173 const char sig =
'B';
10174 const char cit =
'C';
10175 const char link =
'D';
10176 const char plain =
'E';
10177 const char l1 =
'F';
10178 const char l2 =
'G';
10179 const char l3 =
'H';
10180 const char l4 =
'I';
10184 std::size_t ii = 0;
10185 std::size_t iii = 0;
10190 bool ready =
false;
10192 bool delim =
false;
10193 bool signature =
false;
10194 bool citation =
false;
10195 bool hyperlink =
false;
10196 std::size_t cl = 0;
10197 bool cl_lock =
false;
10202 if(NULL == article)
10204 PRINT_ERROR(
"Article display request without content ignored (bug)");
10207 gui_check_article(article);
10208 articleText = article;
10209 articleDisplay->buffer(articleText);
10211 #if !UI_AW_REFERENCES
10213 if (1 == articleText->findchar_forward(0, 0x1DU, &pos))
10215 articleText->remove(articleText->line_start(pos),
10216 articleText->line_end(pos) + 1);
10218 #endif // ! UI_AW_REFERENCES
10221 gui_process_shy(articleText);
10224 style = articleText->text();
10225 if(NULL == style) { len = 0; }
10226 else { len = std::strlen(style); }
10227 if(INT_MAX < len) { len = INT_MAX; }
10228 for(i = 0; i < len; ++i)
10230 if(
'\n' == style[i])
10245 if(
' ' == c || 0x09 == (
int) c ||
'>' == c ||
'"' == c)
10251 if(sol && (
'|' == style[i] ||
'!' == style[i]))
10253 if(!hyperlink) { citation =
true; }
10256 if(sol) { sol =
false; delim =
true; ss = 0; cl = 0; ii = 0; }
10261 if(
'|' == style[i])
10265 for(iiii = i - ii; iiii < i; ++iiii)
10267 if(
'_' != articleText->byte_at((
int) iiii)) {
break; }
10271 for(iiii = 0; iiii <= ii; ++iiii)
10273 style[i - iiii] = plain;
10285 if(
'_' != style[i]) { hs = bold; }
else { hs = plain; }
10288 if(
'|' == style[i] && 79U <= iii) { ready =
true; }
10289 else if(
'_' == style[i]) { ++iii; }
10290 if(
':' == style[i]) { hs = plain; }
10296 if(
'-' == style[i] && !ii) { ss = 1; }
10297 if(
'-' == style[i] && 1U == ii && 1 == ss) { ss = 2; }
10298 if(
' ' == style[i] && 2U == ii && 2 == ss)
10301 if((
char) 0x0A == style[i + 1U])
10303 if(gui_last_sig_separator(&style[i + 1U]))
10305 style[i] = sig; style[i - 1U] = sig; style[i - 2U] = sig;
10312 while(NULL != url[url_i])
10314 if(!std::strncmp(&style[i], url[url_i], url_len[url_i]))
10326 if(
' ' == c || 0x09 == (
int) c ||
'<' == c ||
'"' == c)
10330 else { delim =
false; }
10336 if(
'>' == style[i]) { cl_lock =
false; }
10337 else { cl_lock =
true; }
10339 if(
'>' == style[i] && !cl_lock) { ++cl; }
10340 if(
'>' != style[i] &&
' ' != style[i] && (
char) 9 != style[i])
10344 if(4U < cl) { cl = 1; }
10347 case 1: { style[i] = l1;
break; }
10348 case 2: { style[i] = l2;
break; }
10349 case 3: { style[i] = l3;
break; }
10350 case 4: { style[i] = l4;
break; }
10351 default: { style[i] = plain;
break; }
10356 if(signature) { style[i] = sig; }
10357 if(citation && !signature) { style[i] = cit; }
10358 if(hyperlink) { style[i] = link; }
10361 articleStyle =
new Fl_Text_Buffer((
int) len, 0);
10362 if(NULL != style) { articleStyle->text(style); }
10363 std::free((
void*) style);
10366 articleDisplay->highlight_data(articleStyle, styles, styles_len,
'A', NULL,
10370 if (1 == articleText->findchar_forward(0, 0x1DU, &pos))
10372 articleText->replace(pos, pos + 1,
" ");
10380 ArticleWindow::ArticleWindow(
const char* article,
const char* label) :
10381 UI_WINDOW_CLASS(795, 395, label)
10391 FL_FOREGROUND_COLOR,
10397 FL_FOREGROUND_COLOR,
10405 Fl_Button* buttonp;
10406 int y, w, h, gy, gh, bw;
10410 const char* q = NULL;
10411 Fl_Text_Buffer* tb;
10412 const char* hdr = NULL;
10421 articleText = NULL;
10422 articleStyle = NULL;
10437 raw =
new char[std::strlen(article) + (std::size_t) 1];
10438 std::strcpy(raw, article);
10441 eoh = std::strstr(raw,
"\r\n\r\n");
10446 SC(
"Do not use non-ASCII for the translation of this item")
10447 fl_message_title(S("Error"));
10448 fl_alert("%s", S("Processing of article failed"));
10456 tb =
new Fl_Text_Buffer(0, 0);
10458 hdr = printHeaderFields(alt_hier->
child[0]->
header);
10468 mimeData =
new MIMEContent(alt_hier->
child[0]->
header, q);
10470 gui_decode_mime_entities(tb, mimeData,
10474 callback(cancel_cb, (
void*)
this);
10481 articleGroup =
new Fl_Group(0, 0, 795, 395);
10482 articleGroup->begin();
10485 gui_set_default_font();
10486 fl_measure(S(
"Cancel"), w = 0, h = 0);
10492 articleDisplay =
new My_Text_Display(0, 0, 795, 395 - gh);
10493 articleDisplay->textfont(FL_COURIER);
10496 styles =
new Fl_Text_Display::Style_Table_Entry[styles_len];
10497 styles[0].color = FL_FOREGROUND_COLOR;
10498 styles[0].font = FL_COURIER_BOLD;
10499 styles[0].size = articleDisplay->textsize();
10500 styles[0].attr = 0;
10501 for(ii = 1; ii < styles_len; ++ii)
10503 styles[ii].color = styles_colors[ii];
10504 styles[ii].font = articleDisplay->textfont();
10505 styles[ii].size = articleDisplay->textsize();
10506 styles[ii].attr = 0;
10510 resizable(articleDisplay);
10512 gp =
new Fl_Group(0, gy, 795, gh);
10517 new Fl_Box(0, gy, bw, gh);
10518 new Fl_Box(795 - bw, gy, bw, gh);
10519 buttonp =
new Fl_Button(795 - bw + 15, y, w, h, S(
"Cancel"));
10520 buttonp->callback(cancel_cb, (
void*)
this);
10522 bp =
new Fl_Box(bw, gy, 795 - (2 * bw), gh);
10527 articleGroup->end();
10528 articleGroup->resizable(articleDisplay);
10529 resizable(articleGroup);
10535 size_range(2 * bw, 100, 0, 0);
10536 #if !CFG_DB_DISABLE
10537 Fl::visual(FL_DOUBLE | FL_INDEX);
10538 #endif // CFG_DB_DISABLE
10548 ArticleWindow::~ArticleWindow(
void)
10550 if(NULL != mimeData) {
delete mimeData; }
10552 articleDisplay->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
10553 if(articleStyle)
delete articleStyle;
10554 if(styles) {
delete[] styles; }
10555 articleDisplay->buffer(dummyTb);
10556 if(articleText)
delete articleText;
10565 void ArticleSrcWindow::save_cb_i(
void)
10569 SC(
"Do not use characters for the translation that cannot be")
10570 SC("converted to the ISO 8859-1 character set for this item.")
10571 SC("Leave the original
string in place if in doubt.")
10572 const
char* title = S("Save article source code");
10575 fl_file_chooser_ok_label(S("Save"));
10576 if(NULL != suggested_pathname)
10578 pathname = fl_file_chooser(title,
"*", suggested_pathname, 0);
10579 if(NULL != pathname)
10582 rv = gui_check_pathname(pathname);
10589 SC(
"Do not use non-ASCII for the translation of this item")
10590 fl_message_title(S("Error"));
10591 fl_alert("%s", S("Operation failed"));
10603 ArticleSrcWindow::ArticleSrcWindow(const
char* article, const
char* label) :
10604 UI_WINDOW_CLASS(795, 395, label)
10609 int y, w, h, gy, gh, bw;
10610 int w1, w2, h1, h2;
10612 const char* ap = NULL;
10615 unsigned int octet;
10623 len = std::strlen(article);
10624 srcArticle =
new char[++len];
10625 std::strcpy(srcArticle, article);
10629 srcText =
new Fl_Text_Buffer();
10630 srcStyle =
new Fl_Text_Buffer();
10632 if(NULL == ap) { srcText->insert(0,
"Conversion to POSIX form failed"); }
10635 srcText->insert(0, ap);
10637 buflen = srcText->length();
10640 srcStyle->insert(i,
"A");
10641 octet = (
unsigned int) (
unsigned char) srcText->byte_at(i);
10642 num[0] = (char) (
unsigned char) octet;
10645 || 0x09U == octet )
10648 srcText->replace(i, i + 1, num);
10649 if(!toggle) { style =
"BB"; }
else { style =
"CC"; }
10650 srcStyle->replace(i, i + 1, style);
10651 buflen = srcText->length();
10655 else { toggle = 0; }
10659 gui_check_article(srcText);
10663 callback(cancel_cb, (
void*)
this);
10670 srcGroup =
new Fl_Group(0, 0, 795, 395);
10674 gui_set_default_font();
10675 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
10676 fl_measure(S(
"Save"), w2 = 0, h2 = 0);
10677 if(w1 > w2) { w = w1; }
else { w = w2; }
10678 if(h1 > h2) { h = h1; }
else { h = h2; }
10684 srcDisplay =
new Fl_Text_Display(0, 0, 795, 395 - gh);
10685 srcDisplay->textfont(FL_COURIER);
10686 srcDisplay->buffer(srcText);
10687 resizable(srcDisplay);
10689 styles =
new Fl_Text_Display::Style_Table_Entry[3];
10690 styles[0].color = FL_FOREGROUND_COLOR;
10691 styles[0].font = FL_COURIER;
10692 styles[0].size = srcDisplay->textsize();
10693 styles[0].attr = 0;
10694 styles[1].color = FL_COLOR_CUBE + (Fl_Color) 35;
10695 styles[1].font = FL_COURIER;
10696 styles[1].size = srcDisplay->textsize();
10697 styles[1].attr = 0;
10698 styles[2].color = FL_RED;
10699 styles[2].font = FL_COURIER;
10700 styles[2].size = srcDisplay->textsize();
10701 styles[2].attr = 0;
10702 srcDisplay->highlight_data(srcStyle, styles, 3,
'A', NULL, NULL);
10704 gp =
new Fl_Group(0, gy, 795, gh);
10709 new Fl_Box(0, gy, bw, gh);
10710 p =
new Fl_Button(15, y, w, h, S(
"Save"));
10711 p->callback(save_cb, (
void*)
this);
10712 new Fl_Box(795 - bw, gy, bw, gh);
10713 p =
new Fl_Button(795 - bw + 15, y, w, h, S(
"Cancel"));
10714 p->callback(cancel_cb, (
void*)
this);
10716 bp =
new Fl_Box(bw, gy, 795 - (2 * bw), gh);
10722 srcGroup->resizable(srcDisplay);
10723 resizable(srcGroup);
10729 size_range(2 * bw, 100, 0, 0);
10730 #if !CFG_DB_DISABLE
10731 Fl::visual(FL_DOUBLE | FL_INDEX);
10732 #endif // CFG_DB_DISABLE
10740 ArticleSrcWindow::~ArticleSrcWindow(
void)
10743 srcDisplay->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
10746 srcDisplay->buffer(dummyTb);
10748 delete[] srcArticle;
10761 int ComposeWindow::searchHeaderField(
const char* name,
int* start,
int* end)
10765 unsigned int c = (
unsigned int)
'\n';
10770 rv = compHeader->search_forward(sp, name, start, 1);
10774 if(0 < *start) { c = compHeader->char_at(*start - 1); }
10775 if((
unsigned int)
'\n' != c)
10784 rv = compHeader->findchar_forward(*start, (
unsigned int)
'\n', end);
10785 if(1 == rv) { res = 0; }
10789 if((
unsigned int)
' ' == compHeader->char_at(*end + 1)
10790 && (
unsigned int)
'\n' != compHeader->char_at(*end + 2))
10792 rv = compHeader->findchar_forward(*end + 1,
10793 (
unsigned int)
'\n', end);
10794 if(1 != rv) { res = -1; }
10820 const char* ComposeWindow::extractHeaderField(
const char* name)
10828 rv = searchHeaderField(name, &start, &end);
10832 rv = compHeader->search_forward(start,
": ", &pos, 1);
10836 res = compHeader->text_range(pos, end);
10853 int ComposeWindow::replaceHeaderField(
const char* name,
const char* new_body)
10861 rv = searchHeaderField(name, &start, &end);
10865 rv = compHeader->search_forward(start,
": ", &pos, 1);
10872 compHeader->replace(pos, end, new_body);
10889 void ComposeWindow::deleteHeaderField(
const char* name)
10895 rv = searchHeaderField(name, &start, &end);
10896 if(!rv) { compHeader->remove(start, end + 1); }
10909 int ComposeWindow::checkArticleBody(
const char* body)
10913 const char* sig_delim;
10914 const char* sig = NULL;
10918 bool check =
false;
10919 std::size_t
lines = 0;
10924 len = std::strlen(body);
10929 sig_delim = std::strstr(p,
"\n-- \n");
10930 if(NULL == sig_delim) {
break; }
10931 else { sig = p = &sig_delim[1]; }
10933 if(NULL != sig) { len = (std::size_t) (sig - body); }
10935 for(i = 0; i < len; ++i)
10937 if(0x0A == (
int) body[i]) { sol =
true; check =
false;
continue; }
10938 if(sol) { ++
lines; }
10939 if(sol &&
'>' != body[i]) { check =
true; }
10945 if(
' ' != body[i] && 0x09 != (
int) body[i]) { res = 0;
break; }
10949 if(res && (std::size_t) 1 >=
lines &&
'>' != body[0]) { res = 0; }
10959 void ComposeWindow::change_cb_i(Fl_Widget* w)
10962 const char* subject_new;
10965 std::size_t len = 8;
10968 subject = subjectField->value();
10970 subject_new = fl_input(
"%s",
"", S(
"New subject:"));
10971 if(NULL != subject_new)
10973 if(std::strlen(subject_new))
10977 q = std::strstr(
subject,
" (was: ");
10981 len += std::strlen(subject_new) + std::strlen(q);
10982 p =
new char[++len];
10983 std::strcpy(p, subject_new);
10985 subjectField->value(p);
10992 q = std::strstr(
subject,
"Re: ");
10994 len += std::strlen(subject_new) + std::strlen(
subject);
10995 p =
new char[++len];
10996 std::strcpy(p, subject_new);
10997 std::strcat(p,
" (was: ");
10999 std::strcat(p,
")");
11000 subjectField->value(p);
11011 void ComposeWindow::style_update_cb_i(
int pos,
int nInserted,
int nDeleted,
11012 int nRestyled,
const char* deletedText,
11013 Fl_Text_Buffer* style,
11014 Fl_Text_Editor* editor)
11024 std::size_t p72, p78;
11027 if(0 > nInserted || 0 > nDeleted)
11029 PRINT_ERROR(
"Invalid parameter in compose window style update CB");
11034 if(!nInserted && !nDeleted) {
return; }
11042 buf =
new char[(std::size_t) (nInserted + 1)];
11044 else { buf = sbuf; }
11045 std::memset((
void*) buf,
'A', (std::size_t) nInserted);
11046 buf[nInserted] = 0;
11047 style->replace(pos, pos + nDeleted, buf);
11052 style->remove(pos, pos + nDeleted);
11056 start = editor->buffer()->line_start(pos);
11057 end = editor->buffer()->line_end(pos + nInserted);
11058 lines = 1 + editor->buffer()->count_lines(pos, end);
11059 for(i = 0; i <
lines; ++i)
11061 buf = editor->buffer()->line_text(start);
11062 if(NULL == buf) {
continue; }
11063 len = std::strlen(buf);
11066 std::memset((
void*) buf,
'A', len);
11072 while((std::size_t) next - (std::size_t) start < len)
11074 if(72 == pil) { p72 = (std::size_t) next - (std::size_t) start; }
11075 if(78 == pil++) { p78 = (std::size_t) next - (std::size_t) start; }
11076 next = editor->buffer()->next_char(next);
11080 std::memset((
void*) &buf[p72],
'B', p78 - p72);
11084 std::memset((
void*) &buf[p78],
'C', len - p78);
11087 style->replace(start, start + (
int) len, buf);
11089 start = editor->buffer()->skip_lines(start, 1);
11090 std::free((
void*) buf);
11094 editor->redisplay_range(pos, end);
11101 void ComposeWindow::cancel_cb_i(Fl_Widget* w)
11104 if(Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape)
11109 mainWindow->composeWindow = NULL;
11110 Fl::delete_widget(w);
11112 mainWindow->composeComplete();
11121 void ComposeWindow::send_cb_i(Fl_Widget* w)
11131 const char* newsgroups;
11133 const char* organization;
11135 const char* cancel_lock1;
11136 const char* cancel_lock;
11138 const char* injection_date;
11139 const char* header;
11141 const char* expires;
11142 bool free_subject =
false;
11145 bool fup2_present =
false;
11148 newsgroups = newsgroupsField->value();
11149 len = std::strlen(newsgroups);
11152 SC(
"Do not use non-ASCII for the translation of this item")
11153 fl_message_title(S("Error"));
11154 fl_alert("%s", S("Newsgroups list is empty"));
11161 for(i = 0; i < len; ++i)
11163 if(
',' == q[i] ||
'.' == q[i]
11164 ||
'+' == q[i] ||
'-' == q[i] ||
'_' == q[i])
11168 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11169 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11170 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11174 if(
',' == q[0] ||
',' == q[len - (std::size_t) 1]) { rv = -1; }
11175 if(
'.' == q[0] ||
'.' == q[len - (std::size_t) 1]) { rv = -1; }
11178 SC(
"Do not use non-ASCII for the translation of this item")
11179 fl_message_title(S("Error"));
11180 fl_alert("%s", S("Invalid content in Newsgroups header field"));
11184 rv = replaceHeaderField(
"Newsgroups", newsgroups);
11187 SC(
"Do not use non-ASCII for the translation of this item")
11188 fl_message_title(S("Error"));
11189 fl_alert("%s", S("Replacement of Newsgroups in header failed"));
11198 subject = subjectField->value();
11201 SC(
"Do not use non-ASCII for the translation of this item")
11202 fl_message_title(S("Error"));
11203 fl_alert("%s", S("Subject is empty"));
11211 if(!rv) { free_subject =
true; }
11213 rv = replaceHeaderField(
"Subject",
subject);
11216 SC(
"Do not use non-ASCII for the translation of this item")
11217 fl_message_title(S("Error"));
11218 fl_alert("%s", S("Replacement of Subject in header failed"));
11229 organization = extractHeaderField(
"Organization");
11230 if(NULL != organization)
11237 std::strlen(
"Organization: "));
11238 if(0 < rv) { rv = 0; }
11241 rv = replaceHeaderField(
"Organization", q);
11245 std::free((
void*) organization);
11248 SC(
"Do not use non-ASCII for the translation of this item")
11249 fl_message_title(S("Error"));
11250 fl_alert("%s", S("Encoding of Organization header field failed"));
11259 rv = searchHeaderField(
"MIME-Version", &start, &end);
11262 SC(
"Do not use non-ASCII for the translation of this item")
11263 fl_message_title(S("Error"));
11264 fl_alert("%s", S("Bug: Mandatory MIME declaration not found"));
11270 if(!archiveButton->value())
11272 if(replaceHeaderField(
"Archive",
"no"))
11274 compHeader->insert(start,
"Archive: no\n");
11277 else { deleteHeaderField(
"Archive"); }
11279 q = distriField->value();
11282 len = std::strlen(q);
11286 for(i = 0; i < len; ++i)
11288 if(
',' == q[i] ||
'+' == q[i] ||
'-' == q[i] ||
'_' == q[i])
11292 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11293 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11294 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11298 if(
',' == q[0] ||
',' == q[len - (std::size_t) 1]) { rv = -1; }
11302 p = (
char*) std::malloc(len + (std::size_t) 1);
11303 if(NULL == p) { rv = -1; }
11307 for(i = 0; i < len; ++i)
11311 #if defined(__cplusplus) && __cplusplus >= 199711L
11312 p[i] = (char) std::tolower((
int) (
unsigned char) q[i]);
11313 #else // defined(__cplusplus) && __cplusplus >= 199711L
11315 p[i] = (char) tolower((
int) (
unsigned char) q[i]);
11316 #endif // defined(__cplusplus) && __cplusplus >= 199711L
11322 if(NULL != std::strstr(p,
"all")) { rv = -1; }
11327 SC(
"Do not use non-ASCII for the translation of this item")
11328 fl_message_title(S("Error"));
11330 S("Invalid content in Distribution header field"));
11334 else if(NULL == std::strstr(p, "world"))
11336 if(replaceHeaderField(
"Distribution", p))
11338 compHeader->insert(start,
"\n");
11339 compHeader->insert(start, p);
11340 compHeader->insert(start,
"Distribution: ");
11343 else { deleteHeaderField(
"Distribution"); }
11344 std::free((
void*) p);
11347 else { deleteHeaderField(
"Distribution"); }
11351 expires = expireField->value();
11352 if(NULL != expires)
11354 if(std::strlen(expires))
11358 SC(
"Do not use non-ASCII for the translation of this item")
11359 fl_message_title(S("Error"));
11360 fl_alert("%s", S("Invalid
date for Expires header field"));
11365 if(replaceHeaderField(
"Expires", q))
11367 compHeader->insert(start,
"\n");
11368 compHeader->insert(start, q);
11369 compHeader->insert(start,
"Expires: ");
11371 std::free((
void*) q);
11375 else { deleteHeaderField(
"Expires"); }
11380 q = keywordField->value();
11383 len = std::strlen(q);
11387 for(i = 0; i < len; ++i)
11390 if(
',' == q[i] ||
'!' == q[i] ||
'#' == q[i] ||
'$' == q[i]
11391 ||
'%' == q[i] ||
'&' == q[i] ||
'+' == q[i]
11392 ||
'-' == q[i] ||
'/' == q[i] ||
'=' == q[i]
11393 ||
'?' == q[i] ||
'^' == q[i] ||
'_' == q[i]
11394 ||
'{' == q[i] ||
'|' == q[i] ||
'}' == q[i]
11395 ||
'~' == q[i] ||
' ' == q[i])
11399 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11400 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11401 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11407 if(
',' == q[0] ||
',' == q[len]
11408 ||
' ' == q[0] ||
' ' == q[len])
11414 SC(
"Do not use non-ASCII for the translation of this item")
11415 fl_message_title(S("Error"));
11417 S("Invalid content in Keywords header field"));
11421 if(replaceHeaderField(
"Keywords", q))
11423 compHeader->insert(start,
"\n");
11424 compHeader->insert(start, q);
11425 compHeader->insert(start,
"Keywords: ");
11430 else { deleteHeaderField(
"Keywords"); }
11435 q = fup2Field->value();
11438 len = std::strlen(q);
11442 for(i = 0; i < len; ++i)
11444 if(
',' == q[i] ||
'.' == q[i]
11445 ||
'+' == q[i] ||
'-' == q[i] ||
'_' == q[i])
11449 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11450 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11451 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11455 if(
',' == q[0] ||
',' == q[len - (std::size_t) 1])
11459 if(
'.' == q[0] ||
'.' == q[len - (std::size_t) 1])
11465 SC(
"Do not use non-ASCII for the translation of this item")
11466 fl_message_title(S("Error"));
11468 S("Invalid content in Followup-To header field"));
11472 if(replaceHeaderField(
"Followup-To", q))
11474 compHeader->insert(start,
"\n");
11475 compHeader->insert(start, q);
11476 compHeader->insert(start,
"Followup-To: ");
11477 fup2_present =
true;
11482 else { deleteHeaderField(
"Followup-To"); }
11490 msgid = extractHeaderField(
"Message-ID");
11493 std::free((
void*)
msgid);
11494 if(std::strlen(fqdn))
11499 replaceHeaderField(
"Message-ID",
msgid);
11502 rv = searchHeaderField(
"Cancel-Lock", &start, &end);
11506 deleteHeaderField(
"Cancel-Lock");
11510 if(NULL != cancel_lock1 || NULL != cancel_lock)
11512 compHeader->insert(start,
"\n");
11513 if(NULL != cancel_lock)
11515 compHeader->insert(start, cancel_lock);
11516 compHeader->insert(start,
" ");
11518 if(NULL != cancel_lock1)
11520 compHeader->insert(start, cancel_lock1);
11521 compHeader->insert(start,
" ");
11523 compHeader->insert(start,
"Cancel-Lock:");
11537 date = extractHeaderField(
"Date");
11540 std::free((
void*)
date);
11542 rv = replaceHeaderField(
"Date",
date);
11546 SC(
"Do not use non-ASCII for the translation of this item")
11547 fl_message_title(S("Error"));
11548 fl_alert("%s", S("Updating Date header field failed"));
11557 injection_date = extractHeaderField(
"Injection-Date");
11558 if(NULL != injection_date)
11560 std::free((
void*) injection_date);
11562 rv = replaceHeaderField(
"Injection-Date", injection_date);
11566 SC(
"Do not use non-ASCII for the translation of this item")
11567 fl_message_title(S("Error"));
11568 fl_alert("%s", S("Updating Injection-Date header field failed"));
11578 if(std::strchr(newsgroupsField->value(), (int)
',') && !fup2_present)
11580 SC(
"Do not use non-ASCII for the translation of this item")
11581 fl_message_title(S("Warning"));
11582 rv = !fl_choice("%s", S("Cancel"),
11584 S("Xpost without Followup-To\nReally continue?"));
11591 header = compHeader->text();
11592 body = compText->text();
11593 if(NULL == header || NULL == body)
11595 SC(
"Do not use non-ASCII for the translation of this item")
11596 fl_message_title(S("Error"));
11597 fl_alert("%s", S("Out of memory"));
11601 lenh = std::strlen(header);
11602 lenb = std::strlen(body);
11606 SC(
"Do not use non-ASCII for the translation of this item")
11607 fl_message_title(S("Error"));
11608 fl_alert("%s", S("Message body is empty"));
11613 if(checkArticleBody(body))
11615 SC(
"Do not use non-ASCII for the translation of this item")
11616 fl_message_title(S("Error"));
11617 rv = !fl_choice("%s", S("Cancel"),
11619 S("Message body contains no own content"));
11624 p = (
char*) std::malloc(lenh + lenb + (std::size_t) 1);
11627 std::strcpy(p, header);
11628 std::strcat(p, body);
11630 mainWindow->articlePost(UI_CB_START, p);
11634 std::free((
void*) header);
11635 std::free((
void*) body);
11645 void ComposeWindow::uri_insert_cb_i(Fl_Widget* w)
11647 const char* scheme = uriSchemeField->value();
11649 const char* body_raw = uriBodyField->value();
11650 const char* body = NULL;
11653 if(std::strlen(scheme))
11655 if(!std::strncmp(scheme,
"http", 4))
11659 else if(!std::strncmp(scheme,
"ftp", 3))
11663 else if(!std::strncmp(scheme,
"news", 4))
11667 else if(!std::strncmp(scheme,
"mailto", 6))
11676 SC(
"Do not use non-ASCII for the translation of this item")
11677 fl_message_title(S("Error"));
11678 fl_alert("%s", S("Creation of URI failed"));
11683 compEditor->insert(
"<");
11685 compEditor->insert(scheme);
11687 compEditor->insert(
":");
11691 compEditor->insert(
"//");
11694 compEditor->insert(body);
11695 uriBodyField->value(
"");
11697 compEditor->insert(
">");
11699 compTabs->value(compGroup);
11700 Fl::focus(compEditor);
11702 if(body != body_raw) {
enc_free((
void*) body); }
11709 ComposeWindow::ComposeWindow(
const char* label,
const char* header,
11711 bool super) : UI_WINDOW_CLASS(795, 395, label)
11713 static const char label_ch[] =
"1-----------------------------------------"
11714 "-------------------------72->|-78->|";
11721 int y, w, h, gy, gh, bw, sh, hh;
11722 int w1, w2, w3, w4, h1, h2, h3;
11723 const char* signature;
11725 const char* newsgroups;
11726 const char**
groups = NULL;
11729 unsigned int signature_warnings = 0;
11730 const char* uri_header;
11731 const char* distribution = NULL;
11732 int dist_msg_flag = 0;
11735 SC(
"Preserve the spaces at beginning and end")
11736 const
char* label_content = S(" Content ");
11737 const
char* label_uri_encoder = S(" URI encoder ");
11738 const
char* label_advanced = S(" Advanced ");
11739 SC("Preserve the colon")
11740 const
char* label_subject = S("Subject:");
11741 const
char* label_change = S("Change");
11742 const
char* label_send = S("Send");
11743 const
char* label_cancel = S("Cancel");
11744 const
char* label_insert = S("Insert");
11748 callback(cancel_cb, (
void*) this);
11751 compHeader = new Fl_Text_Buffer();
11752 compHeader->text(header);
11753 currentStyle = new Fl_Text_Buffer();
11754 compText = new Fl_Text_Buffer();
11755 compText->add_modify_callback(style_update_cb, (
void*) this);
11761 compTabs = new Fl_Tabs(0, 0, 795, 395);
11764 compGroup =
new Fl_Group(0, th - tg, 795, 395 - th + tg, label_content);
11765 compGroup->begin();
11768 gui_set_default_font();
11769 fl_measure(label_send, w1 = 0, h1 = 0);
11770 fl_measure(label_cancel, w2 = 0, h2 = 0);
11771 if(w1 > w2) { w = w1; }
else { w = w2; }
11772 if(h1 > h2) { h = h1; }
else { h = h2; }
11776 gy = 395 - th - gh;
11779 subjectGroup =
new Fl_Group(0, th, 795, sh);
11780 subjectGroup->begin();
11782 gui_set_default_font();
11783 fl_measure(label_subject, w3 = 0, h3 = 0);
11785 fl_measure(label_change, w4 = 0, h3 = 0);
11787 subjectField =
new Fl_Input(w3, th, 795 - w3 - w4, sh,
11789 subjectField->align(FL_ALIGN_LEFT);
11790 subject = extractHeaderField(
"Subject");
11793 subjectField->value(
subject);
11796 p =
new Fl_Button(795 - w4, th, w4, sh, label_change);
11798 S(
"Change subject and cite old one with was: prefix in parenthesis")
11800 p->callback(change_cb, (
void*)
this);
11802 subjectGroup->end();
11803 subjectGroup->resizable(subjectField);
11806 chp =
new Fl_Box(0, th + sh, 795, hh, label_ch);
11807 chp->labelfont(FL_COURIER);
11808 chp->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
11810 compEditor =
new Fl_Text_Editor(0, th + sh + hh, 795,
11811 395 - th - sh - hh - gh);
11812 compEditor->textfont(FL_COURIER);
11813 compEditor->show_insert_position();
11814 resizable(compEditor);
11816 styles =
new Fl_Text_Display::Style_Table_Entry[3];
11817 styles[0].color = FL_FOREGROUND_COLOR;
11818 styles[0].font = FL_COURIER;
11819 styles[0].size = compEditor->textsize();
11820 styles[0].attr = 0;
11821 styles[1].color = FL_COLOR_CUBE + (Fl_Color) 35;
11822 styles[1].font = FL_COURIER;
11823 styles[1].size = compEditor->textsize();
11824 styles[1].attr = 0;
11825 styles[2].color = FL_RED;
11826 styles[2].font = FL_COURIER;
11827 styles[2].size = compEditor->textsize();
11828 styles[2].attr = 0;
11829 compEditor->highlight_data(currentStyle, styles, 3,
'A', NULL, NULL);
11831 compEditor->buffer(compText);
11832 if(NULL != article)
11834 compText->insert(0, article);
11838 if (NULL != ca) { gui_cite_content(compText, ca, hdr->
groups); }
11840 gui_check_article(compText);
11842 if(super) { compEditor->insert_position(0); }
11843 else { compEditor->insert_position(compText->length()); }
11846 if(NULL != signature)
11850 if(!super) { compEditor->buffer()->append(
"\n"); }
11853 compEditor->buffer()->append(
"-- \n");
11855 compEditor->buffer()->append(signature);
11860 gp =
new Fl_Group(0, th + gy, 795, gh);
11865 new Fl_Box(0, th + gy, bw, gh);
11866 p =
new Fl_Button(15, y, w, h, label_send);
11867 p->callback(send_cb, (
void*)
this);
11868 new Fl_Box(795 - bw, gy, bw, gh);
11869 p =
new Fl_Button(795 - bw + 15, y, w, h, label_cancel);
11870 p->callback(cancel_cb, (
void*)
this);
11872 bp =
new Fl_Box(bw, th + gy, 795 - (2 * bw), gh);
11878 compGroup->resizable(compEditor);
11882 uriEncGroup =
new Fl_Group(0, th - tg, 795, 395 - th + tg,
11883 label_uri_encoder);
11884 uriEncGroup->begin();
11887 uri_header = S(
"Percent encoder for clickable URIs");
11888 uriHeaderField =
new Fl_Box(5, y, 795 - 10, sh, uri_header);
11889 uriHeaderField->labelfont(FL_HELVETICA_BOLD);
11891 uriSchemeField =
new Fl_Input_Choice(5, y, 795 - 10, sh,
11893 uriSchemeField->tooltip(S(
"Only the selectable schemes are supported"));
11894 uriSchemeField->align(FL_ALIGN_TOP_LEFT);
11895 uriSchemeField->add(
"http");
11896 uriSchemeField->add(
"https");
11897 uriSchemeField->add(
"ftp");
11898 uriSchemeField->add(
"news");
11899 uriSchemeField->add(
"mailto");
11900 uriSchemeField->input()->readonly(1);
11901 uriSchemeField->value(0);
11903 uriBodyField =
new Fl_Input(5, y, 795 - 10, sh, S(
"Body for URI:"));
11904 uriBodyField->align(FL_ALIGN_TOP_LEFT);
11907 fl_measure(label_insert, w1 = 0, h1 = 0);
11910 gp =
new Fl_Group(0, y, 795, h);
11913 p =
new Fl_Button(5, y, w, h, label_insert);
11914 p->callback(uri_insert_cb, (
void*)
this);
11915 fillSpace =
new Fl_Box(5 + w, y, 795 - (10 + w), h);
11918 gp->resizable(fillSpace);
11921 fillSpace =
new Fl_Box(5, y, 795 - 10, 1);
11923 uriEncGroup->end();
11924 uriEncGroup->resizable(fillSpace);
11928 advancedGroup =
new Fl_Group(0, th - tg, 795, 395 - th + tg,
11930 advancedGroup->begin();
11933 newsgroupsField =
new Fl_Input(5, y, 795 - 10, sh,
"Newsgroups:");
11934 newsgroupsField->align(FL_ALIGN_TOP_LEFT);
11935 newsgroupsField->tooltip(S(
"Comma separated list"));
11936 newsgroups = extractHeaderField(
"Newsgroups");
11937 if(NULL != newsgroups)
11939 newsgroupsField->value(newsgroups);
11946 while(NULL !=
groups[i])
11954 std::free((
void*) newsgroups);
11957 fup2Field =
new Fl_Input_Choice(5, y, 795 - 10, sh,
"Followup-To:");
11958 fup2Field->align(FL_ALIGN_TOP_LEFT);
11959 fup2Field->tooltip(S(
"Comma separated list"));
11960 fup2Field->add(
"poster");
11965 if(NULL == hdr->
groups[i]) {
break; }
11969 if(!i && NULL == hdr->
groups[1]) {
break; }
11970 fup2Field->add(hdr->
groups[i]);
11975 if(NULL != hdr->
fup2 && std::strlen(hdr->
fup2))
11977 fup2Field->value(hdr->
fup2);
11982 keywordField =
new Fl_Input_Choice(5, y, 795 - 10, sh,
"Keywords:");
11983 keywordField->align(FL_ALIGN_TOP_LEFT);
11984 keywordField->tooltip(S(
"Comma separated list"));
11985 if(!testGrp) { keywordField->add(
"ignore"); }
11989 std::printf(
"%s: %s"
11990 "Setting keywords from config file for test group\n",
11995 expireField =
new Fl_Input(5, y, 795 - 10, sh,
"Expires:");
11996 expireField->align(FL_ALIGN_TOP_LEFT);
11997 expireField->tooltip(
11998 S(
"Use date in ISO 8601 format YYYY-MM-DD")
12001 distriField =
new Fl_Input_Choice(5, y, 795 - 10, sh,
"Distribution:");
12002 distriField->align(FL_ALIGN_TOP_LEFT);
12003 if(NULL != hdr && NULL != hdr->
dist && std::strlen(hdr->
dist))
12008 std::printf(
"%s: %sFollowing former distribution\n",
12011 distriField->value(hdr->
dist);
12017 newsgroups = extractHeaderField(
"Newsgroups");
12018 if(NULL != newsgroups)
12032 std::free((
void*) newsgroups);
12037 std::printf(
"%s: %sSetting distribution as suggested\n",
12039 distriField->value(distribution);
12042 else { distriField->value(
"world"); }
12044 distriField->add(
"world");
12045 distriField->add(
"local");
12046 distriField->tooltip(
12047 S(
"Use country code or comma separated list of country codes")
12050 archiveButton =
new Fl_Check_Button(5, y, 795 - 10, sh,
"Archive");
12051 archiveButton->set();
12054 fillSpace =
new Fl_Box(5, y, 795 - 10, 1);
12056 advancedGroup->end();
12057 advancedGroup->resizable(fillSpace);
12060 compTabs->resizable(compGroup);
12066 if(!std::strlen(subjectField->value())) { Fl::focus(subjectField); }
12067 else { Fl::focus(compEditor); }
12069 size_range(4 * bw, 395, 0, 0);
12074 SC(
"Do not use non-ASCII for the translation of this item")
12075 fl_message_title(S("Note"));
12076 fl_message("%s", S("Distribution set as suggested by server"));
12082 SC(
"Do not use non-ASCII for the translation of this item")
12083 fl_message_title(S("Error"));
12084 fl_alert("%s", S("Signature has unsupported character set"));
12090 SC(
"Do not use non-ASCII for the translation of this item")
12091 fl_message_title(S("Note"));
12092 fl_message("%s", S("Signature should not be longer than 4
lines"));
12099 #if !CFG_DB_DISABLE
12100 Fl::visual(FL_DOUBLE | FL_INDEX);
12101 #endif // CFG_DB_DISABLE
12108 mainWindow->composeWindowLock = 1;
12109 UI_STATUS(S(
"Waiting for external editor ..."));
12117 ComposeWindow::~ComposeWindow(
void)
12120 compEditor->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
12121 delete currentStyle;
12123 compEditor->buffer(dummyTb);
12149 Fl_Text_Buffer* info;
12150 const char* pass = NULL;
12151 const char* title_psfile;
12157 PRINT_ERROR(
"No thread support available in FLTK");
12164 lockingInitialized =
true;
12167 if(rv) { exitRequest = 1; }
12173 SC(
"This section is for the button labels of popup windows")
12174 fl_cancel = S(
"Cancel");
12175 fl_close = S(
"Close");
12183 SC(
"This section is for the text buffer warning messages")
12184 Fl_Text_Buffer::file_encoding_warning_message
12185 = S(
"Invalid encoding detected, trying to convert data");
12189 SC(
"This section is for the file chooser labels")
12190 Fl_File_Chooser::all_files_label = S(
"*");
12191 Fl_File_Chooser::custom_filter_label = S(
"Custom filter");
12192 Fl_File_Chooser::existing_file_label
12193 = S(
"Please choose an existing file!");
12194 Fl_File_Chooser::favorites_label = S(
"Favorites");
12195 Fl_File_Chooser::add_favorites_label = S(
"Add to favorites");
12196 Fl_File_Chooser::manage_favorites_label = S(
"Manage favorites");
12197 Fl_File_Chooser::filesystems_label = S(
"File systems");
12198 Fl_File_Chooser::new_directory_label = S(
"New directory?");
12199 Fl_File_Chooser::new_directory_tooltip = S(
"Create a new directory.");
12200 Fl_File_Chooser::preview_label = S(
"Preview");
12201 Fl_File_Chooser::hidden_label = S(
"Show hidden files");
12202 Fl_File_Chooser::filename_label = S(
"Filename:");
12203 Fl_File_Chooser::save_label = S(
"Save");
12204 SC(
"The translation for this should not be much longer!")
12205 Fl_File_Chooser::show_label = S(
"Show:");
12210 SC(
"This section is for the print dialog labels")
12211 SC(
"Do not use characters for the translation that cannot be")
12212 SC(
"converted to the ISO 8859-1 character set for this item.")
12213 SC(
"Leave the original string in place if in doubt.")
12214 Fl_Printer::dialog_title = S(
"Print");
12215 Fl_Printer::dialog_printer = S(
"Printer");
12216 Fl_Printer::dialog_range = S(
"Print range");
12217 Fl_Printer::dialog_copies = S(
"Copies");
12218 Fl_Printer::dialog_all = S(
"All");
12219 Fl_Printer::dialog_pages = S(
"Pages");
12220 Fl_Printer::dialog_from = S(
"From:");
12221 Fl_Printer::dialog_to = S(
"To:");
12222 Fl_Printer::dialog_properties = S(
"Properties ...");
12223 Fl_Printer::dialog_copyNo = S(
"Copies:");
12224 Fl_Printer::dialog_print_button = S(
"Print");
12225 Fl_Printer::dialog_cancel_button = S(
"Cancel");
12226 Fl_Printer::dialog_print_to_file = S(
"Print to file");
12231 SC(
"This section is for the printer property dialog labels")
12232 SC(
"Do not use characters for the translation that cannot be")
12233 SC(
"converted to the ISO 8859-1 character set for this item.")
12234 SC(
"Leave the original string in place if in doubt.")
12235 Fl_Printer::property_title = S(
"Printer properties");
12236 Fl_Printer::property_pagesize = S(
"Page size:");
12237 Fl_Printer::property_mode = S(
"Output mode:");
12238 Fl_Printer::property_use = S(
"Use");
12239 Fl_Printer::property_save = S(
"Save");
12240 Fl_Printer::property_cancel = S(
"Cancel");
12245 SC(
"This section is for the print to file chooser dialog label")
12246 SC(
"Do not use characters for the translation that cannot be")
12247 SC(
"converted to the ISO 8859-1 character set for this item.")
12248 SC(
"Leave the original string in place if in doubt.")
12249 title_psfile = S(
"Select a .ps file");
12252 Fl_PostScript_File_Device::file_chooser_title = title_psfile;
12264 #if CFG_CMPR_DISABLE
12267 #endif // CFG_CMPR_DISABLE
12270 dummyTb =
new Fl_Text_Buffer(0, 0);
12271 mainWindow =
new MainWindow(CFG_NAME);
12274 mainWindow->size_range(w, h, 0, 0);
12279 mainWindow->resize(x, y, w, h);
12283 mainWindow->setTilingX(tx);
12284 mainWindow->setTilingY(ty);
12285 mainWindow->redraw();
12288 fl_message_hotspot(0);
12290 #if USE_WINDOW_ICON
12292 mainWindow->default_icon(&mainIcon);
12293 #endif // USE_WINDOW_ICON
12298 #if !CFG_DB_DISABLE
12299 Fl::visual(FL_DOUBLE | FL_INDEX);
12300 #endif // CFG_DB_DISABLE
12301 mainWindow->show(argc, argv);
12306 gui_set_default_font();
12309 info =
new Fl_Text_Buffer;
12310 text = gui_greeting();
12313 mainWindow->articleUpdate(info);
12317 text = S(
"Possible security vulnerability in TLS module detected!");
12319 # if !CFG_TLS_WARNING_DISABLE
12321 # else // !CFG_TLS_WARNING_DISABLE
12323 # endif // !CFG_TLS_WARNING_DISABLE
12326 SC(
"Do not use non-ASCII for the translation of this item")
12327 fl_message_title(S(
"Warning"));
12328 fl_alert(
"%s", text);
12330 #endif // CFG_USE_TLS
12338 SC(
"Do not use non-ASCII for the translation of this item")
12339 fl_message_title(S(
"Note"));
12340 rv = fl_choice(
"%s", S(
"Skip"),
12342 S(
"TLS certificate revocation list \x28\x43RL\x29\nupdate interval elapsed. Update now?"));
12346 std::printf(
"%s: %sTLS certificate CRL updates suppressed\n",
12351 #endif // CFG_USE_TLS
12360 if(NULL == pass) { exitRequest = 1;
break; }
12366 SC(
"Do not use non-ASCII for the translation of this item")
12367 fl_message_title(S(
"Warning"));
12368 fl_alert(
"%s", S(
"Empty password is not supported"));
12375 MainWindow::group_list_refresh_timer_cb((
void*) mainWindow);
12389 offset_correction_x = x - mainWindow->x();
12390 if(20 < offset_correction_x) { offset_correction_x = 0; }
12391 offset_correction_y = y - mainWindow->y();
12392 if(20 < offset_correction_y) { offset_correction_y = 0; }
12409 static const char* tmpfile = NULL;
12410 static long int editor_pid;
12411 static bool editor_term_lock =
false;
12417 if(NULL == mainWindow) { res = 1; }
12421 if(NULL != protocolConsole) { protocolConsole->update(); }
12427 if(NULL == mainWindow->composeWindow)
12429 mainWindow->composeWindowLock = 0;
12431 switch(mainWindow->composeWindowLock)
12436 if(exitRequest) { res = 1; }
12443 if(NULL != tmpfile)
12445 rv = gui_save_to_file(tmpfile, mainWindow->composeWindow
12446 ->compEditor->buffer());
12450 if(!rv) { error =
false; }
12460 UI_STATUS(S(
"Starting external editor failed."));
12461 mainWindow->composeWindowLock = 3;
12463 else { mainWindow->composeWindowLock = 2; }
12472 if(exitRequest && !editor_term_lock)
12476 editor_term_lock =
true;
12482 if(rv) {
UI_STATUS(S(
"External editor reported error.")); }
12486 UI_STATUS(S(
"External editor reported success."));
12487 rv = mainWindow->composeWindow
12488 ->compEditor->buffer()->loadfile(tmpfile);
12491 mainWindow->composeWindow
12492 ->compEditor->buffer()
12493 ->append(S(
"[Importing data from editor failed]"));
12498 mainWindow->composeWindowLock = 3;
12504 editor_term_lock =
false;
12505 mainWindow->composeWindow->show();
12506 mainWindow->composeWindowLock = 0;
12511 PRINT_ERROR(
"Error in external editor state machine (bug)");
12529 if(NULL != mainWindow)
12544 mainWindow->groupStateExport();
12550 lockingInitialized =
false;
12554 if(NULL != mainWindow)
12587 return(fl_utf8locale());
12603 case UI_CB_COOKIE_SERVER:
12605 rv = Fl::awake(MainWindow::serverconf_cb, (
void*) mainWindow);
12608 case UI_CB_COOKIE_GROUPLIST:
12610 rv = Fl::awake(MainWindow::subscribe_cb1, (
void*) mainWindow);
12613 case UI_CB_COOKIE_GROUPLABELS:
12615 rv = Fl::awake(MainWindow::subscribe_cb2, (
void*) mainWindow);
12618 case UI_CB_COOKIE_GROUPPROPOSAL:
12620 rv = Fl::awake(MainWindow::groupproposal_cb, (
void*) mainWindow);
12623 case UI_CB_COOKIE_GROUPINFO1:
12625 rv = Fl::awake(MainWindow::refresh_cb1, (
void*) mainWindow);
12628 case UI_CB_COOKIE_GROUPINFO2:
12630 rv = Fl::awake(MainWindow::refresh_cb2, (
void*) mainWindow);
12633 case UI_CB_COOKIE_GROUP:
12635 rv = Fl::awake(MainWindow::group_cb, (
void*) mainWindow);
12638 case UI_CB_COOKIE_OVERVIEW:
12640 rv = Fl::awake(MainWindow::overview_cb, (
void*) mainWindow);
12643 case UI_CB_COOKIE_HEADER:
12645 rv = Fl::awake(MainWindow::header_cb, (
void*) mainWindow);
12648 case UI_CB_COOKIE_BODY:
12650 rv = Fl::awake(MainWindow::body_cb, (
void*) mainWindow);
12653 case UI_CB_COOKIE_MOTD:
12655 rv = Fl::awake(MainWindow::motd_cb, (
void*) mainWindow);
12658 case UI_CB_COOKIE_ARTICLE:
12660 rv = Fl::awake(MainWindow::article_cb, (
void*) mainWindow);
12663 case UI_CB_COOKIE_SRC:
12665 rv = Fl::awake(MainWindow::src_cb, (
void*) mainWindow);
12668 case UI_CB_COOKIE_POST:
12670 rv = Fl::awake(MainWindow::post_cb, (
void*) mainWindow);
12675 PRINT_ERROR(
"Can't assign cookie to callback function");
12682 PRINT_ERROR(
"Registering awake callback failed (fatal error)");
12711 if(lockingInitialized)
12714 if(res) { res = -1; }
12731 if(lockingInitialized)