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_File_Chooser.H>
45 #include <FL/Fl_Group.H>
46 #include <FL/Fl_Input.H>
47 #include <FL/Fl_Input_Choice.H>
48 #include <FL/Fl_Menu_.H>
49 #include <FL/Fl_Menu_Bar.H>
50 #include <FL/Fl_Menu_Item.H>
51 #include <FL/Fl_Multi_Browser.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>
77 #include <libbasexx-0/basexx_version.h>
79 #include <libssiconv-0/iconv.h>
81 #include <libjpiconv-0/iconv.h>
83 #include <libuciconv-0/iconv.h>
124 #define USE_LINE_COUNT 0
127 #define USE_ARTICLE_NUMBER 0
134 #define MAIN_ERR_PREFIX "GUI: "
141 #define UI_COLOR_MENU_SELECTION (Fl_Color) 0x50505000UL
143 #define UI_COLOR_PROGRESS_BAR (Fl_Color) 0x50505000UL
145 #define UI_COLOR_RADIO_BUTTON (Fl_Color) 0x50505000UL
149 #define UI_STYLES_LEN 9
153 #define UI_CB_START 0
154 #define UI_CB_CONTINUE 1
155 #define UI_CB_FINISH 2
160 #define UI_CB_COOKIE_SERVER 0U
161 #define UI_CB_COOKIE_GROUPLIST 1U
162 #define UI_CB_COOKIE_GROUPLABELS 2U
163 #define UI_CB_COOKIE_GROUPPROPOSAL 3U
164 #define UI_CB_COOKIE_GROUPINFO1 4U
165 #define UI_CB_COOKIE_GROUPINFO2 5U
166 #define UI_CB_COOKIE_GROUP 6U
167 #define UI_CB_COOKIE_OVERVIEW 7U
168 #define UI_CB_COOKIE_HEADER 8U
169 #define UI_CB_COOKIE_BODY 9U
170 #define UI_CB_COOKIE_MOTD 10U
171 #define UI_CB_COOKIE_ARTICLE 11U
172 #define UI_CB_COOKIE_SRC 12U
173 #define UI_CB_COOKIE_POST 13U
181 #define UI_ENC_NONE 0 // No encryption
182 #define UI_ENC_STRONG 1 // TLS with strong encryption and forward secrecy
183 #define UI_ENC_WEAK 2 // TLS compatibility mode offering weak cipher suites
188 #define UI_AUTH_NONE 0 // No authentication
189 #define UI_AUTH_USER 1 // AUTHINFO USER/PASS as defined in RFC 4643
194 #define UI_CAC_MIN 10 // Lower limit: 1
195 #define UI_CAC_MAX 50000 // Upper limit: INT_MAX
199 #define UI_HDR_BUFSIZE (std::size_t) 998
202 #define UI_STATIC_STYLE_BUFSIZE (std::size_t) 80
205 #define UI_XPOST_LIMIT (std::size_t) 10
211 #define UI_AW_REFERENCES 0
215 # define UI_WINDOW_CLASS Fl_Window
216 #else // CFG_DB_DISABLE
217 # define UI_WINDOW_CLASS Fl_Double_Window
218 #endif // CFG_DB_DISABLE
221 #define USE_WINDOW_ICON 0
222 #ifdef FL_ABI_VERSION
223 # if 10303 <= FL_ABI_VERSION
225 # undef USE_WINDOW_ICON
226 # define USE_WINDOW_ICON 1
227 # endif // 10303 <= FL_ABI_VERSION
228 #endif // FL_ABI_VERSION
252 inline void serverReplace(
const char* s)
254 std::strncpy(server, s, 128); server[127] = 0;
256 inline void serviceReplace(
const char* s)
258 std::strncpy(service, s, 6); service[5] = 0;
260 inline void serviceReplace(
unsigned int i)
262 std::ostringstream ss;
264 if(0xFFFFU < i) { i = 0xFFFFU; }
265 ss << i << std::flush;
266 const std::string& s = ss.str();
267 std::strncpy(service, s.c_str(), 6); service[5] = 0;
274 struct MIMEContentListElement
281 const char* filename;
282 MIMEContentListElement* next;
288 MIMEContentListElement* partList;
290 const char* createMessageHeader(
const char*, std::size_t);
291 MIMEContentListElement* decodeElement(
const char*, std::size_t,
char*,
292 bool,
bool, std::size_t*);
293 MIMEContentListElement* initElement(
const char*, std::size_t,
297 inline bool is_multipart(
void) {
return(multipart); }
298 inline std::size_t parts(
void) {
return(partNum); }
299 inline const char* part_header(std::size_t i)
301 MIMEContentListElement* mcle = partList;
303 if(!partNum || i >= partNum) {
return(NULL); }
306 while(i--) { mcle = mcle->next; }
307 return(mcle->header);
310 inline const char* part(std::size_t i,
enc_mime_cte* te,
313 MIMEContentListElement* mcle = partList;
315 if(!partNum || i >= partNum) {
return(NULL); }
318 while(i--) { mcle = mcle->next; }
320 if(NULL != ctp) { *ctp = &mcle->ct; }
321 return(mcle->content);
326 MIMEContentListElement* mcle = partList;
328 if(!partNum || i >= partNum) {
return(ENC_CD_UNKNOWN); }
331 while(i--) { mcle = mcle->next; }
335 inline const char* filename(std::size_t i)
337 MIMEContentListElement* mcle = partList;
339 if(!partNum || i >= partNum) {
return(NULL); }
342 while(i--) { mcle = mcle->next; }
343 return(mcle->filename);
352 class My_Multi_Browser :
public Fl_Multi_Browser
357 My_Multi_Browser(
int X,
int Y,
int W,
int H,
const char* L = 0)
358 : Fl_Multi_Browser(X, Y, W, H, L) { }
362 class My_Text_Display :
public Fl_Text_Display
369 My_Text_Display(
int X,
int Y,
int W,
int H,
const char* L = 0)
370 : Fl_Text_Display(X, Y, W, H, L) { linkPushed = -1; }
374 class My_Tree :
public Fl_Tree
378 bool positions_recalculated;
379 Fl_Tree_Item* current_article;
383 inline void update_in_progress(
bool state) { updated = !state; }
384 inline bool update_in_progress(
void) {
return !updated; }
385 inline void not_drawn(
void) { positions_recalculated =
false; }
386 inline bool drawn(
void)
389 if (0 == w() || 0 == h()) {
return true; }
390 return(positions_recalculated);
392 inline void draw(
void)
396 positions_recalculated =
true;
398 inline void store_current(Fl_Tree_Item* ti)
400 current_article = ti;
402 inline void select_former(
void)
404 if(NULL != current_article)
406 set_item_focus(current_article);
407 select_only(current_article, 0);
410 My_Tree(
int X,
int Y,
int W,
int H,
const char* L = 0)
411 : Fl_Tree(X, Y, W, H, L)
414 positions_recalculated =
false;
415 current_article = NULL;
420 class ServerCfgWindow :
public UI_WINDOW_CLASS
427 Fl_Input* scfgHostname;
428 Fl_Input* scfgService;
429 Fl_Radio_Round_Button* scfgTlsOff;
430 Fl_Radio_Round_Button* scfgTlsStrong;
431 Fl_Radio_Round_Button* scfgTlsWeak;
432 Fl_Radio_Round_Button* scfgAuthOff;
433 Fl_Radio_Round_Button* scfgAuthUser;
439 inline void ok_cb_i(
void) { finished = 1; }
440 static void ok_cb(Fl_Widget*,
void* w)
442 ((ServerCfgWindow*) w)->ok_cb_i();
446 inline void cancel_cb_i(
void) { finished = -1; }
447 static void cancel_cb(Fl_Widget*,
void* w)
449 ((ServerCfgWindow*) w)->cancel_cb_i();
453 inline void enc_cb_i(
bool enc)
457 scfgService->value(
"nntp");
458 #if !CFG_NNTP_AUTH_UNENCRYPTED
459 scfgAuthOff->setonly();
460 grpAuth->deactivate();
465 scfgService->value(
"nntps");
469 static void enc_off_cb(Fl_Widget*,
void* w)
471 ((ServerCfgWindow*) w)->enc_cb_i(
false);
473 static void enc_on_cb(Fl_Widget*,
void* w)
475 ((ServerCfgWindow*) w)->enc_cb_i(
true);
480 ServerCfgWindow(ServerConfig*,
const char*);
481 ~ServerCfgWindow(
void);
485 class IdentityCfgWindow :
public UI_WINDOW_CLASS
491 Fl_Input* replytoName;
492 Fl_Input* replytoEmail;
495 inline void ok_cb_i(
void);
496 static void ok_cb(Fl_Widget*,
void* w)
498 ((IdentityCfgWindow*) w)->ok_cb_i();
502 static void cancel_cb(Fl_Widget*,
void* w)
504 Fl::delete_widget((Fl_Widget*) w);
507 IdentityCfgWindow(
const char*);
508 ~IdentityCfgWindow(
void);
512 class MiscCfgWindow :
public UI_WINDOW_CLASS
518 Fl_Check_Button* cmprEnable;
519 Fl_Check_Button* localTime;
520 Fl_Check_Button* uagentEnable;
522 Fl_Check_Button* qsSpace;
523 Fl_Check_Button* qsUnify;
526 inline void ok_cb_i(
void);
527 static void ok_cb(Fl_Widget*,
void* w)
529 ((MiscCfgWindow*) w)->ok_cb_i();
533 static void cancel_cb(Fl_Widget*,
void* w)
535 Fl::delete_widget((Fl_Widget*) w);
538 MiscCfgWindow(
const char*);
539 ~MiscCfgWindow(
void);
544 class SearchWindow :
public UI_WINDOW_CLASS
547 Fl_Input* searchField;
548 Fl_Check_Button* cisEnable;
549 const char** currentSearchString;
552 inline void ok_cb_i(
void);
553 static void ok_cb(Fl_Widget*,
void* w)
555 ((SearchWindow*) w)->ok_cb_i();
556 ((SearchWindow*) w)->finished = 1;
560 static void cancel_cb(Fl_Widget*,
void* w)
562 ((SearchWindow*) w)->finished = -1;
566 SearchWindow(
const char*,
const char**);
572 class ProtocolConsole :
public UI_WINDOW_CLASS
575 Fl_Text_Display* consoleDisplay;
577 Fl_Text_Buffer* consoleText;
582 static void exit_cb(Fl_Widget*,
void* w)
584 Fl::delete_widget((Fl_Widget*) w);
589 ProtocolConsole(
const char*);
590 ~ProtocolConsole(
void);
594 class SubscribeWindow :
public UI_WINDOW_CLASS
597 Fl_Group* subscribeGroup;
598 Fl_Tree* subscribeTree;
603 inline void ok_cb_i(
void);
604 static void ok_cb(Fl_Widget*,
void* w)
606 ((SubscribeWindow*) w)->ok_cb_i();
610 static void cancel_cb(Fl_Widget*,
void* w)
612 Fl::delete_widget((Fl_Widget*) w);
616 inline void tree_cb_i(
void)
620 if(FL_TREE_REASON_SELECTED == subscribeTree->callback_reason())
623 ti = subscribeTree->callback_item();
624 if(NULL == ti->user_data()) { subscribeTree->deselect(ti, 0); }
627 static void tree_cb(Fl_Widget*,
void* w)
629 ((SubscribeWindow*) w)->tree_cb_i();
632 inline void add(
const char* entry,
core_anum_t num,
const char* label)
635 std::ostringstream labelString;
637 ti = subscribeTree->find_item(entry);
638 if(NULL == ti) { ti = subscribeTree->add(entry); }
641 PRINT_ERROR(
"Adding group to subscription tree failed");
646 ti->labelfont(FL_HELVETICA_BOLD);
647 ti->user_data((
void*) entry);
648 labelString << ti->label() <<
" (" << num <<
")";
649 if(NULL != label) { labelString <<
" | " << label; }
660 const std::string& ls = labelString.str();
661 ti->label(ls.c_str());
664 inline void collapseAll(
void)
668 for(i = subscribeTree->first(); i; i = subscribeTree->next(i))
670 subscribeTree->close(i, 0);
672 subscribeTree->open(subscribeTree->root(), 0);
676 ~SubscribeWindow(
void);
680 class MIDSearchWindow :
public UI_WINDOW_CLASS
687 inline void ok_cb_i(
void);
688 static void ok_cb(Fl_Widget*,
void* w)
690 ((MIDSearchWindow*) w)->ok_cb_i();
694 static void cancel_cb(Fl_Widget*,
void* w)
696 Fl::delete_widget((Fl_Widget*) w);
699 MIDSearchWindow(
const char*);
700 ~MIDSearchWindow(
void);
704 class BugreportWindow :
public UI_WINDOW_CLASS
707 Fl_Text_Display* bugreportDisplay;
708 Fl_Text_Buffer* bugreportText;
711 static void exit_cb(Fl_Widget*,
void* w)
713 Fl::delete_widget((Fl_Widget*) w);
717 BugreportWindow(
const char*,
const char*);
718 ~BugreportWindow(
void);
722 class LicenseWindow :
public UI_WINDOW_CLASS
725 Fl_Text_Display* licenseDisplay;
726 Fl_Text_Buffer* licenseText;
729 static void exit_cb(Fl_Widget*,
void* w)
731 Fl::delete_widget((Fl_Widget*) w);
735 LicenseWindow(
const char*);
736 ~LicenseWindow(
void);
740 class MotdWindow :
public UI_WINDOW_CLASS
743 Fl_Text_Display* motdDisplay;
744 Fl_Text_Buffer* motdText;
747 static void exit_cb(Fl_Widget*,
void* w)
749 Fl::delete_widget((Fl_Widget*) w);
753 MotdWindow(
const char*,
const char*);
758 class ArticleWindow :
public UI_WINDOW_CLASS
761 Fl_Group* articleGroup;
762 My_Text_Display* articleDisplay;
763 Fl_Text_Buffer* articleText;
764 Fl_Text_Buffer* articleStyle;
765 Fl_Text_Display::Style_Table_Entry* styles;
767 MIMEContent* mimeData;
771 void articleUpdate(Fl_Text_Buffer* article);
774 static void cancel_cb(Fl_Widget*,
void* w)
776 Fl::delete_widget((Fl_Widget*) w);
780 ArticleWindow(
const char*,
const char*);
781 ~ArticleWindow(
void);
785 class ArticleSrcWindow :
public UI_WINDOW_CLASS
789 Fl_Text_Display* srcDisplay;
790 Fl_Text_Buffer* srcText;
791 Fl_Text_Buffer* srcStyle;
792 Fl_Text_Display::Style_Table_Entry* styles;
794 const char* pathname;
797 inline void save_cb_i(
void);
798 static void save_cb(Fl_Widget*,
void* w)
800 ((ArticleSrcWindow*) w)->save_cb_i();
804 static void cancel_cb(Fl_Widget*,
void* w)
806 Fl::delete_widget((Fl_Widget*) w);
810 ArticleSrcWindow(
const char*,
const char*);
811 ~ArticleSrcWindow(
void);
815 class ComposeWindow :
public UI_WINDOW_CLASS
819 Fl_Group* subjectGroup;
820 Fl_Input* subjectField;
822 Fl_Group* uriEncGroup;
823 Fl_Group* advancedGroup;
824 Fl_Text_Buffer* compHeader;
825 Fl_Text_Display::Style_Table_Entry* styles;
826 Fl_Text_Buffer* currentStyle;
827 Fl_Text_Buffer* compText;
829 Fl_Box* uriHeaderField;
830 Fl_Input_Choice* uriSchemeField;
831 Fl_Input* uriBodyField;
833 Fl_Input* newsgroupsField;
834 Fl_Input_Choice* fup2Field;
835 Fl_Input_Choice* keywordField;
836 Fl_Input* expireField;
837 Fl_Input_Choice* distriField;
838 Fl_Check_Button* archiveButton;
842 inline void change_cb_i(
void);
843 static void change_cb(Fl_Widget*,
void* w)
845 ((ComposeWindow*) w)->change_cb_i();
849 inline void style_update_cb_i(
int pos,
int nInserted,
int nDeleted,
850 Fl_Text_Buffer* style,
851 Fl_Text_Editor* editor);
852 static void style_update_cb(
int pos,
int nInserted,
int nDeleted,
853 int nRestyled,
const char* deletedText,
858 ((ComposeWindow*) w)->style_update_cb_i(pos, nInserted, nDeleted,
859 ((ComposeWindow*) w)->currentStyle,
860 ((ComposeWindow*) w)->compEditor);
864 inline void send_cb_i(
void);
865 static void send_cb(Fl_Widget*,
void* w)
867 ((ComposeWindow*) w)->send_cb_i();
871 inline void cancel_cb_i(Fl_Widget*);
872 static void cancel_cb(Fl_Widget*,
void* w)
874 ((ComposeWindow*) w)->cancel_cb_i((Fl_Widget*) w);
878 inline void uri_insert_cb_i(
void);
879 static void uri_insert_cb(Fl_Widget*,
void* w)
881 ((ComposeWindow*) w)->uri_insert_cb_i();
884 int searchHeaderField(
const char*,
int*,
int*);
885 const char* extractHeaderField(
const char*);
886 int replaceHeaderField(
const char*,
const char*);
887 void deleteHeaderField(
const char*);
888 int checkArticleBody(
const char*);
890 Fl_Text_Editor* compEditor;
891 ComposeWindow(
const char*,
const char*,
const char*,
const char*,
893 ~ComposeWindow(
void);
897 class MainWindow :
public UI_WINDOW_CLASS
922 EVENT_SUBSCRIBE_EXIT,
925 EVENT_GL_PROPOSAL_EXIT,
928 EVENT_GL_REFRESH_EXIT,
934 EVENT_AT_REFRESH_EXIT,
954 EVENT_MOTD_VIEW_EXIT,
957 EVENT_SCROLL_NEXT_EXIT,
968 Fl_Progress* progressBar;
969 std::ostringstream aboutString;
970 ComposeWindow* composeWindow;
971 int composeWindowLock;
972 unsigned int hyperlinkStyle;
973 int hyperlinkPosition;
978 mainWindowState mainState;
979 SubscribeWindow* subscribeWindow;
980 Fl_Tile* contentGroup;
981 Fl_Tile* contentGroup2;
982 #if CFG_COCOA_SYS_MENUBAR
983 Fl_Sys_Menu_Bar* menu;
984 #else // CFG_COCOA_SYS_MENUBAR
986 #endif // CFG_COCOA_SYS_MENUBAR
987 std::size_t groupcount;
989 My_Multi_Browser* groupList;
992 My_Tree* articleTree;
995 My_Text_Display* text;
997 Fl_Text_Display::Style_Table_Entry* styles;
999 Fl_Text_Buffer* currentStyle;
1000 Fl_Text_Buffer* currentArticle;
1002 const char* currentSearchString;
1003 int currentSearchPosition;
1007 int groupSelect_cb_state;
1008 int groupRefresh_cb_state;
1009 float progress_percent_value;
1010 char progress_percent_label[5];
1011 bool progress_skip_update;
1012 MIMEContent* mimeData;
1021 std::size_t group_num;
1022 std::size_t group_list_index;
1027 inline void progress_release_cb_i(
void)
1029 progress_skip_update =
false;
1031 static void progress_release_cb(
void* w)
1033 ((MainWindow*) w)->progress_release_cb_i();
1037 inline void exit_cb_i(
void);
1038 static void exit_cb(Fl_Widget*,
void* w)
1040 ((MainWindow*) w)->exit_cb_i();
1044 inline void print_cb_i(
void);
1045 static void print_cb(Fl_Widget*,
void* w)
1047 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1049 Fl::option(Fl::OPTION_PRINTER_USES_GTK,
false);
1050 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1051 ((MainWindow*) w)->print_cb_i();
1055 inline void asave_cb_i(
void);
1056 static void asave_cb(Fl_Widget*,
void* w)
1058 ((MainWindow*) w)->asave_cb_i();
1062 inline void server_cb_i(
void)
1064 updateServer(UI_CB_START);
1066 static void server_cb(Fl_Widget*,
void* w)
1068 ((MainWindow*) w)->server_cb_i();
1072 inline void config_cb_i(
void);
1073 static void config_cb(Fl_Widget*,
void* w)
1075 ((MainWindow*) w)->config_cb_i();
1079 inline void identity_cb_i(
void);
1080 static void identity_cb(Fl_Widget*,
void* w)
1082 ((MainWindow*) w)->identity_cb_i();
1086 inline void about_cb_i(
void);
1087 static void about_cb(Fl_Widget*,
void* w)
1089 ((MainWindow*) w)->about_cb_i();
1093 inline void viewmotd_cb_i(
void)
1095 viewMotd(UI_CB_START);
1097 static void viewmotd_cb(Fl_Widget*,
void* w)
1099 ((MainWindow*) w)->viewmotd_cb_i();
1103 inline void mid_search_cb_i(
void);
1104 static void mid_search_cb(Fl_Widget*,
void* w)
1106 ((MainWindow*) w)->mid_search_cb_i();
1110 inline void bug_cb_i(
void);
1111 static void bug_cb(Fl_Widget*,
void* w)
1113 ((MainWindow*) w)->bug_cb_i();
1117 inline void license_cb_i(
void);
1118 static void license_cb(Fl_Widget*,
void* w)
1120 ((MainWindow*) w)->license_cb_i();
1124 inline void console_cb_i(
void);
1125 static void console_cb(Fl_Widget*,
void* w)
1127 ((MainWindow*) w)->console_cb_i();
1131 inline void gsubscribe_cb_i(
void)
1133 groupSubscribe(UI_CB_START);
1135 static void gsubscribe_cb(Fl_Widget*,
void* w)
1137 ((MainWindow*) w)->gsubscribe_cb_i();
1141 inline void gunsubscribe_cb_i(
void)
1143 std::size_t index = (std::size_t) groupList->value();
1147 fl_message_title(S(
"Warning"));
1148 rv = fl_choice(
"%s", S(
"No"),
1150 S(
"Really unsubscribe group?"));
1155 SC(
"Do not use non-ASCII for the translation of this item")
1156 fl_message_title(S("Error"));
1157 fl_alert("%s", S("No group selected"));
1165 fl_message_title(S(
"Error"));
1166 fl_alert(
"%s", S(
"Unsubscribe operation failed"));
1171 fl_message_title(S(
"Error"));
1172 fl_alert(
"%s", S(
"Exporting group states failed"));
1175 groupListRefresh(UI_CB_START);
1178 static void gunsubscribe_cb(Fl_Widget*,
void* w)
1180 ((MainWindow*) w)->gunsubscribe_cb_i();
1184 inline void grefresh_cb_i(
void)
1186 groupListRefresh(UI_CB_START);
1188 static void grefresh_cb(Fl_Widget*,
void* w)
1190 ((MainWindow*) w)->grefresh_cb_i();
1194 inline void gsort_cb_i(
void)
1199 fl_message_title(S(
"Warning"));
1200 rv = fl_choice(
"%s", S(
"No"),
1202 S(
"Really sort group list?"));
1210 groupListRefresh(UI_CB_START);
1213 static void gsort_cb(Fl_Widget*,
void* w)
1215 ((MainWindow*) w)->gsort_cb_i();
1219 inline void gselect_cb_i(
void)
1221 groupSelect(UI_CB_START, groupList->value());
1223 static void gselect_cb(Fl_Widget*,
void* w)
1225 ((MainWindow*) w)->gselect_cb_i();
1229 inline void nug_cb_i(
void)
1232 int groups = groupList->size();
1233 int current = groupList->value();
1237 for(current ? i = current - 1 : i = 0; i < groups; ++i)
1239 ur = groupGetUnreadNo(subscribedGroups[i].lwm,
1240 subscribedGroups[i].hwm, group_list[i].info);
1243 groupList->deselect();
1244 groupList->select(++i);
1245 groupSelect(UI_CB_START, i);
1251 groups = current - 1;
1256 static void nug_cb(Fl_Widget*,
void* w)
1258 ((MainWindow*) w)->nug_cb_i();
1263 inline void thrv_cb_i(
void)
1265 Fl_Menu_Item* mi = (Fl_Menu_Item*) menu->find_item(uthrv_sort_cb);
1270 if(NULL != mi) { mi->activate(); }
1275 if(NULL != mi) { mi->deactivate(); }
1277 if(NULL != currentGroup) { updateTree(); }
1278 #if CFG_COCOA_SYS_MENUBAR
1280 #endif // CFG_COCOA_SYS_MENUBAR
1282 static void thrv_cb(Fl_Widget*,
void* w)
1284 ((MainWindow*) w)->thrv_cb_i();
1289 inline void uthrv_sort_cb_i(
void)
1293 if(NULL != currentGroup) { updateTree(); }
1295 static void uthrv_sort_cb(Fl_Widget*,
void* w)
1297 ((MainWindow*) w)->uthrv_sort_cb_i();
1301 inline void onlyur_cb_i(
void)
1305 if(NULL != currentGroup) { updateTree(); }
1307 static void onlyur_cb(Fl_Widget*,
void* w)
1309 ((MainWindow*) w)->onlyur_cb_i();
1313 inline void wrap_cb_i(
void)
1315 if(Fl_Text_Display::WRAP_AT_BOUNDS != wrapMode)
1317 wrapMode = Fl_Text_Display::WRAP_AT_BOUNDS;
1319 else { wrapMode = Fl_Text_Display::WRAP_NONE; }
1320 text->wrap_mode(wrapMode, 0);
1322 static void wrap_cb(Fl_Widget*,
void* w)
1324 ((MainWindow*) w)->wrap_cb_i();
1328 inline void rot13_cb_i(
void);
1329 static void rot13_cb(Fl_Widget*,
void* w)
1331 ((MainWindow*) w)->rot13_cb_i();
1336 inline void msau_cb_i(
void);
1337 static void msau_cb(Fl_Widget*,
void* w)
1339 ((MainWindow*) w)->msau_cb_i();
1343 inline void mssar(Fl_Tree_Item*);
1344 inline void mssar_cb_i(
void);
1345 static void mssar_cb(Fl_Widget*,
void* w)
1347 ((MainWindow*) w)->mssar_cb_i();
1351 inline void maar_cb_i(
void);
1352 static void maar_cb(Fl_Widget*,
void* w)
1354 ((MainWindow*) w)->maar_cb_i();
1358 inline void magar_cb_i(
void);
1359 static void magar_cb(Fl_Widget*,
void* w)
1361 ((MainWindow*) w)->magar_cb_i();
1365 inline void aselect_cb_i(
void);
1366 static void aselect_cb(Fl_Widget*,
void* w)
1368 ((MainWindow*) w)->aselect_cb_i();
1372 inline void viewsrc_cb_i(
void)
1374 viewSrc(UI_CB_START);
1376 static void viewsrc_cb(Fl_Widget*,
void* w)
1378 ((MainWindow*) w)->viewsrc_cb_i();
1382 inline void compose_cb_i(
void)
1384 articleCompose(
false,
false);
1386 static void compose_cb(Fl_Widget*,
void* w)
1388 ((MainWindow*) w)->compose_cb_i();
1392 inline void reply_cb_i(
void)
1394 articleCompose(
true,
false);
1396 static void reply_cb(Fl_Widget*,
void* w)
1398 ((MainWindow*) w)->reply_cb_i();
1402 inline void cancel_cb_i(
void)
1404 articleCompose(
false,
true);
1406 static void cancel_cb(Fl_Widget*,
void* w)
1408 ((MainWindow*) w)->cancel_cb_i();
1412 inline void supersede_cb_i(
void)
1414 articleCompose(
true,
true);
1416 static void supersede_cb(Fl_Widget*,
void* w)
1418 ((MainWindow*) w)->supersede_cb_i();
1422 inline void email_cb_i(
void)
1426 static void email_cb(Fl_Widget*,
void* w)
1428 ((MainWindow*) w)->email_cb_i();
1432 inline void nua_cb_i(
void)
1434 std::size_t index = (std::size_t) groupList->value();
1438 SC(
"Do not use non-ASCII for the translation of this item")
1439 fl_message_title(S("Error"));
1440 fl_alert("%s", S("No group selected"));
1442 else { ascrolldown_cb(
false); }
1444 static void nua_cb(Fl_Widget*,
void* w)
1446 ((MainWindow*) w)->nua_cb_i();
1450 inline void pra_cb_i(
void)
1455 if(NULL == lastArticleHE)
1457 SC(
"Do not use non-ASCII for the translation of this item")
1458 fl_message_title(S("Error"));
1459 fl_alert("%s", S("No previously read article stored for group"));
1464 len = std::strlen(mid);
1466 if(NULL == searchSelectArticle(&mid[1], len - (std::size_t) 2))
1468 SC(
"Do not use non-ASCII for the translation of this item")
1469 fl_message_title(S("Error"));
1470 fl_alert("%s", "Previous article not found (bug)");
1474 static
void pra_cb(Fl_Widget*,
void* w)
1476 ((MainWindow*) w)->pra_cb_i();
1480 inline void hyperlink_cb_i(
void)
1482 hyperlinkHandler(hyperlinkPosition);
1484 static void hyperlink_cb(Fl_Widget*,
void* w)
1486 ((MainWindow*) w)->hyperlink_cb_i();
1489 void clearTree(
void);
1490 void scrollTree(ui_scroll, Fl_Tree_Item*);
1491 bool checkTreeBranchForUnread(Fl_Tree_Item*);
1492 bool checkTreeBranchForItem(Fl_Tree_Item*, Fl_Tree_Item*);
1494 void updateTree(
void);
1495 inline void collapseTree(
void)
1499 for(i = 0; i < articleTree->root()->children(); ++i)
1501 articleTree->root()->child(i)->close();
1504 void groupSubscribe(
int);
1507 void groupListUpdateEntry(std::size_t);
1508 int groupStateMerge(
void);
1509 void groupSelect(
int,
int);
1511 void groupListGetProposal(
int);
1512 void updateArticleTree(
int);
1513 void articleSelect(
int);
1516 void stripAngleAddress(
char*);
1517 void articleCompose(
bool,
bool);
1518 void sendEmail(
void);
1519 Fl_Tree_Item* searchSelectArticle(
const char*, std::size_t);
1520 void storeMIMEEntityToFile(
const char*,
const char*);
1521 void hyperlinkHandler(
int);
1523 bool stateMachine(
enum mainWindowEvent);
1525 void viewArticle(
int,
const char*);
1526 static void group_list_refresh_timer_cb(
void* w)
1528 ((MainWindow*) w)->groupListRefresh(UI_CB_START);
1534 Fl::add_timeout(iv, group_list_refresh_timer_cb, (
void*) w);
1537 static void serverconf_cb(
void* w)
1539 ((MainWindow*) w)->updateServer(UI_CB_CONTINUE);
1541 static void subscribe_cb1(
void* w)
1543 ((MainWindow*) w)->groupSubscribe(UI_CB_CONTINUE);
1545 static void subscribe_cb2(
void* w)
1547 ((MainWindow*) w)->groupSubscribe(UI_CB_FINISH);
1549 static void groupproposal_cb(
void* w)
1551 ((MainWindow*) w)->groupListGetProposal(UI_CB_CONTINUE);
1553 static void refresh_cb1(
void* w)
1555 ((MainWindow*) w)->groupListRefresh(UI_CB_CONTINUE);
1557 static void refresh_cb2(
void* w)
1559 ((MainWindow*) w)->groupListRefresh(UI_CB_FINISH);
1561 static void group_cb(
void* w)
1563 ((MainWindow*) w)->groupSelect(UI_CB_CONTINUE, 0);
1565 static void overview_cb(
void* w)
1567 ((MainWindow*) w)->updateArticleTree(UI_CB_FINISH);
1569 static void header_cb(
void* w)
1571 ((MainWindow*) w)->updateArticleTree(UI_CB_CONTINUE);
1573 static void body_cb(
void* w)
1575 ((MainWindow*) w)->articleSelect(UI_CB_CONTINUE);
1577 static void motd_cb(
void* w)
1579 ((MainWindow*) w)->viewMotd(UI_CB_CONTINUE);
1581 static void article_cb(
void* w)
1583 ((MainWindow*) w)->viewArticle(UI_CB_CONTINUE, NULL);
1585 static void src_cb(
void* w)
1587 ((MainWindow*) w)->viewSrc(UI_CB_CONTINUE);
1589 static void post_cb(
void* w)
1591 ((MainWindow*) w)->articlePost(UI_CB_CONTINUE, NULL);
1594 inline void asearch_cb_i(
void);
1595 static void asearch_cb(Fl_Widget*,
void* w)
1597 ((MainWindow*) w)->asearch_cb_i();
1599 void ascrolldown_cb(
bool);
1600 void articlePost(
int,
const char*);
1601 inline void composeComplete(
void)
1603 if(!stateMachine(EVENT_COMPOSE_EXIT))
1605 PRINT_ERROR(
"Error in main window state machine");
1608 void calculatePercent(std::size_t, std::size_t);
1609 inline int groupStateExport(
void)
1613 void updateServer(
int);
1614 void groupListRefresh(
int);
1615 inline void groupListImport(
void)
1618 groupListRefresh(UI_CB_START);
1620 void articleUpdate(Fl_Text_Buffer*);
1621 inline int getTilingX(
void) {
return(groupList->w()); }
1622 inline int getTilingY(
void) {
return(articleTree->h()); }
1623 inline void setTilingX(
int tx)
1626 if(50 > tx) { tx = 50; }
1627 if(w() - 50 < tx) { tx = w() - 50; }
1629 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1632 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1634 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1637 inline void setTilingY(
int ty)
1640 if(50 > ty) { ty = 50; }
1641 if(groupList->h() - 50 < ty) { ty = groupList->h() - 50; }
1643 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1646 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1648 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1649 (1, contentGroup2->y() + 140,
1650 1, contentGroup2->y() + ty);
1652 MainWindow(
const char*);
1661 #define UI_STATUS(s) { if(mainWindow) { mainWindow->statusBar->label(s); } }
1664 #define UI_READY() \
1668 mainWindow->progressBar->value(0.0); \
1669 mainWindow->progressBar->label(""); \
1670 mainWindow->default_cursor(FL_CURSOR_DEFAULT); \
1671 mainWindow->busy = false; \
1680 mainWindow->progressBar->value(0.0); \
1681 SC("This string must fit into the progress bar box") \
1682 mainWindow->progressBar->label(S("Busy")); \
1683 mainWindow->default_cursor(FL_CURSOR_WAIT); \
1684 mainWindow->busy = true; \
1689 #define UI_PROGRESS(s, e) \
1693 mainWindow->calculatePercent(s, e); \
1694 if(100.0 == progress_percent_value || !progress_skip_update) \
1696 mainWindow->progressBar->value(progress_percent_value); \
1697 mainWindow->progressBar->copy_label(progress_percent_label); \
1699 if(!mainWindow->busy) \
1701 mainWindow->default_cursor(FL_CURSOR_WAIT); \
1702 mainWindow->busy = true; \
1705 progress_skip_update = true; \
1706 Fl::add_timeout(0.1, progress_release_cb, this); \
1717 #include "pixmaps/pixmaps.c"
1720 static Fl_Pixmap pm_window_icon(xpm_window_icon);
1721 #endif // USE_WINDOW_ICON
1722 static Fl_Pixmap pm_own(xpm_own);
1723 static Fl_Pixmap pm_reply_to_own(xpm_reply_to_own);
1724 static Fl_Pixmap pm_score_down(xpm_score_down);
1725 static Fl_Pixmap pm_score_up(xpm_score_up);
1727 static Fl_Text_Buffer* dummyTb;
1729 static Fl_RGB_Image mainIcon(&pm_window_icon);
1730 #endif // USE_WINDOW_ICON
1731 static MainWindow* mainWindow = NULL;
1732 static ProtocolConsole* protocolConsole = NULL;
1733 static int exitRequest = 0;
1734 static bool lockingInitialized =
false;
1735 static int offset_correction_x;
1736 static int offset_correction_y;
1744 static void gui_set_default_font(
void)
1746 fl_font(FL_HELVETICA, FL_NORMAL_SIZE);
1753 static const char* gui_greeting(
void)
1755 std::ostringstream greetingString;
1761 if(!std::strcmp(CFG_NAME,
"flnews"))
1767 <<
" __/ /_ / / _______ _______ ___ ___ _______\n"
1768 <<
" /_ __/ / / / ___ \\ / ___ \\ / / / / / _____\\\n"
1769 <<
" / / / / / / / / / /__/__/ / /_/|_/ / /__/_____\n"
1770 <<
" / / / / / / / / / /_____ / ___ / ______/ /\n"
1771 <<
"/__/ /__/ /__/ /__/ \\_______/ \\__/ /___/ \\_______/";
1773 else { greetingString << CFG_NAME; }
1774 greetingString <<
"\n\n"
1775 << S(
"A fast and lightweight Usenet newsreader for Unix.") <<
"\n\n"
1778 << S(
"is based in part on the work of the following projects:") <<
"\n"
1779 <<
"- FLTK project (https://www.fltk.org/)" <<
"\n"
1780 <<
"- The Unicode\xC2\xAE Standard (https://home.unicode.org/)" <<
"\n"
1781 <<
" Unicode is a registered trademark of Unicode, Inc. in the" <<
"\n"
1782 <<
" United States and other countries" <<
"\n"
1784 # if CFG_USE_LIBRESSL
1785 <<
"- LibreSSL project (https://www.libressl.org/)" <<
"\n"
1786 # else // CFG_USE_LIBRESSL
1787 <<
"- OpenSSL project (https://www.openssl.org/)" <<
"\n"
1788 # endif // CFG_USE_LIBRESSL
1789 <<
" This product includes software developed by" <<
"\n"
1790 <<
" the OpenSSL Project for use in the OpenSSL Toolkit" <<
"\n"
1791 <<
" This product includes software written by" <<
"\n"
1792 <<
" Tim Hudson <tjh@cryptsoft.com>" <<
"\n"
1793 <<
" This product includes cryptographic software written by" <<
"\n"
1794 <<
" Eric Young <eay@cryptsoft.com>" <<
"\n"
1795 #endif // CFG_USE_TLS
1797 <<
"- zlib compression library (https://zlib.net/)" <<
"\n"
1798 #endif // CFG_USE_ZLIB
1803 const std::string& gs = greetingString.str();
1807 len = std::strlen(s1) + (std::size_t) 1;
1809 std::memcpy(s2, s1, len);
1819 #if CFG_USE_XSI && !CFG_NLS_DISABLE
1820 static const char* gui_utf8_iso(
const char* s)
1822 const char* res = NULL;
1827 if(!fl_utf8locale())
1831 len = fl_utf8toa(s, (
unsigned int) std::strlen(s), NULL, 0);
1832 tmp =
new char[len + 1U];
1833 if(fl_utf8toa(s, (
unsigned int) std::strlen(s), tmp, len + 1U) != len)
1837 else { res = (
const char*) tmp; }
1842 len = (
unsigned int) std::strlen(s);
1843 tmp =
new char[len + 1U];
1844 std::strncpy(tmp, s, len + 1U);
1845 res = (
const char*) tmp;
1850 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
1859 static int gui_save_to_file(
const char* pathname, Fl_Text_Buffer* tbuf)
1862 char* s = tbuf->text();
1867 std::free((
void*) s);
1885 static void gui_check_article(Fl_Text_Buffer* tbuf)
1889 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1891 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1893 int len = tbuf->length();
1898 int eol = tbuf->line_end(pos);
1900 if(1000 <= eol - pos)
1909 if(INT_MAX > pos) { ++pos; }
1911 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
1917 tbuf->append(
"[Error]\n");
1918 tbuf->append(S(
"Invalid line length"));
1933 static void gui_process_shy(Fl_Text_Buffer* tbuf)
1940 rv = tbuf->findchar_forward(pos_shy, 0x00ADU, &pos_shy);
1944 rv2 = tbuf->next_char(pos_shy);
1945 if(0x000AU == tbuf->char_at(rv2))
1948 tbuf->replace(pos_shy, rv2,
"-");
1950 else { tbuf->remove(pos_shy, rv2); }
1961 static const char* gui_check_re_prefix(
const char* subject)
1963 bool prefix_replaced;
1965 if((std::size_t) 3 <= std::strlen(subject))
1971 prefix_replaced =
false;
1972 if( (!std::strncmp(subject,
"Re:", 3) &&
' ' != subject[3])
1973 || !std::strncmp(subject,
"RE:", 3)
1974 || !std::strncmp(subject,
"re:", 3)
1975 || !std::strncmp(subject,
"AW:", 3)
1976 || !std::strncmp(subject,
"Aw:", 3) )
1979 " replaced with \"Re: \"");
1980 subject = &subject[3];
1981 if(
' ' == subject[0]) { subject = &subject[1]; }
1982 prefix_replaced =
true;
1985 while(prefix_replaced);
1987 if(!std::strncmp(subject,
"Re: ", 4)) { subject = &subject[4]; }
1999 static const char* gui_create_newsgroup_list(
const char** array)
2001 static const char error[] =
"[Error]";
2003 std::size_t size_max = (std::size_t) -1;
2005 std::size_t len = 0;
2009 while(NULL != array[i])
2011 if(UINT_MAX == i) {
break; }
2012 j = std::strlen(array[i]);
2013 if(size_max - len < j) {
break; }
2017 if(!i || (size_max - len < i))
2019 res =
new char[std::strlen(error) + (size_t) 1];
2020 std::strcat(res, error);
2027 res =
new char[len];
2029 for(j = 0; i > j; ++j)
2031 if(j) { std::strcat(res,
","); }
2032 std::strcat(res, array[j]);
2034 res[len - (std::size_t) 1] = 0;
2044 static int gui_last_sig_separator(
char* buf)
2051 p = std::strstr(buf,
"\n-- \n");
2057 q = std::strstr(buf,
"\n________________________________________"
2058 "_______________________________________|\n");
2059 if(NULL != q && p > q) { res = 1; }
2071 static void gui_cite_content(Fl_Text_Buffer* compText,
const char* ca,
2074 const char* ngl = gui_create_newsgroup_list(nga);
2087 case 0: { qm =
">";
break; }
2088 case 1: { qm =
"> ";
break; }
2091 PRINT_ERROR(
"Quoting style configuration not supported");
2098 if(compText->length())
2100 while(compText->char_at(pos))
2103 if((
unsigned int)
'>' == compText->char_at(pos))
2108 compText->insert(pos, qm);
2116 c = compText->char_at(pos);
2117 next = compText->char_at(compText->next_char(pos));
2118 if((
unsigned int)
'>' == c)
2120 if((
unsigned int)
' ' == next)
2123 compText->remove(pos + 1, pos + 2);
2126 pos = compText->next_char(pos);
2127 next = compText->char_at(pos);
2129 while((
unsigned int)
'>' == next || (
unsigned int)
' ' == next);
2135 c = compText->char_at(pos);
2136 next = compText->char_at(compText->next_char(pos));
2137 if((
unsigned int)
'>' == c)
2139 if((
unsigned int)
'>' == next)
2142 compText->insert(++pos,
" ");
2144 else if((
unsigned int)
'>' != next
2145 && (
unsigned int)
' ' != next)
2148 compText->insert(++pos,
" ");
2151 pos = compText->next_char(pos);
2153 while((
unsigned int)
'>' == next || (
unsigned int)
' ' == next);
2157 rv = compText->findchar_forward(pos, (
unsigned int)
'\n',
2159 if(!rv) {
break; }
else { pos = ++pos_found; }
2166 compText->insert(0,
"\n"); compText->insert(0, qm);
2170 if(NULL == intro) { compText->insert(0,
"[Error] wrote:\n"); }
2173 compText->insert(0,
"\n");
2174 compText->insert(0, intro);
2179 compText->append(
"\n");
2189 #define UI_HDR_FIELDS (std::size_t) 14
2190 #define UI_HDR_PAD(s, n) { for(i = 0; i < n; ++i) { s << " "; } }
2193 static const char* f[UI_HDR_FIELDS] =
2206 S(
"Transfer-Encoding"),
2210 std::size_t flen[UI_HDR_FIELDS];
2211 std::size_t fpad[UI_HDR_FIELDS];
2212 std::ostringstream hdrData;
2218 std::size_t largest = 0;
2221 for(i = 0; i < UI_HDR_FIELDS; ++i)
2223 len = std::strlen(f[i]);
2224 #if CFG_USE_XSI && !CFG_NLS_DISABLE
2228 if(INT_MAX < len) { len = INT_MAX; }
2229 rv = fl_utf_nb_char((
const unsigned char*) f[i], (
int) len);
2230 if(0 > rv) { flen[i] = len; }
2231 else { flen[i] = (std::size_t) rv; }
2232 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
2235 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
2237 for(i = 0; i < UI_HDR_FIELDS; ++i)
2239 if(largest < flen[i]) { largest = flen[i]; }
2241 for(i = 0; i < UI_HDR_FIELDS; ++i) { fpad[i] = largest - flen[i]; }
2244 UI_HDR_PAD(hdrData, fpad[0]);
2245 hdrData << f[0] <<
": " << h->
subject <<
"\n";
2249 UI_HDR_PAD(hdrData, fpad[1]);
2250 hdrData << f[1] <<
": " << date <<
"\n";
2252 UI_HDR_PAD(hdrData, fpad[2]);
2253 hdrData << f[2] <<
": " << h->
from <<
"\n";
2258 UI_HDR_PAD(hdrData, fpad[3]);
2259 hdrData << f[3] <<
": " << h->
reply2 <<
"\n";
2262 UI_HDR_PAD(hdrData, fpad[4]);
2263 hdrData << f[4] <<
": ";
2265 while(NULL != h->
groups[i])
2267 if(i) { hdrData <<
","; }
2268 hdrData << h->
groups[i++];
2273 UI_HDR_PAD(hdrData, fpad[5]);
2274 hdrData << f[5] <<
": " << h->
fup2 <<
"\n";
2279 UI_HDR_PAD(hdrData, fpad[6]);
2280 hdrData << f[6] <<
": " << h->
dist <<
"\n";
2283 UI_HDR_PAD(hdrData, fpad[7]);
2284 hdrData << f[7] <<
": " << h->
msgid <<
"\n";
2287 UI_HDR_PAD(hdrData, fpad[8]);
2288 hdrData << f[8] <<
": " << h->
supers <<
"\n";
2292 UI_HDR_PAD(hdrData, fpad[9]);
2293 hdrData << f[9] <<
": " << h->
org <<
"\n";
2297 UI_HDR_PAD(hdrData, fpad[10]);
2298 hdrData << f[10] <<
": " << h->
uagent <<
"\n";
2302 UI_HDR_PAD(hdrData, fpad[10]);
2303 hdrData << f[10] <<
": " << h->
x_newsr <<
"\n";
2307 UI_HDR_PAD(hdrData, fpad[10]);
2308 hdrData << f[10] <<
": " << h->
x_pagent <<
"\n";
2312 UI_HDR_PAD(hdrData, fpad[10]);
2313 hdrData << f[10] <<
": " << h->
x_mailer <<
"\n";
2317 UI_HDR_PAD(hdrData, fpad[11]);
2318 hdrData << f[11] <<
": " << h->
mime_cte <<
"\n";
2322 UI_HDR_PAD(hdrData, fpad[12]);
2323 hdrData << f[12] <<
": " << h->
mime_ct <<
"\n";
2327 UI_HDR_PAD(hdrData, fpad[13]);
2330 hdrData << f[13] <<
":" <<
"\x1D";
2332 while(NULL != h->
refs[i]) { hdrData <<
"[" << i++ <<
"]"; }
2335 hdrData << std::flush;
2346 const std::string& hs = hdrData.str();
2348 len = std::strlen(hs.c_str());
2349 s =
new char[++len];
2350 std::strncpy(s, hs.c_str(), len);
2367 static const char* gui_create_link_to_entity(
const char* msgid,
2370 const char* link = NULL;
2372 const char* confdir = NULL;
2375 std::ostringstream entity_no;
2380 tb.text(
"<file://");
2382 tb.append(
"/.mime/entities/");
2384 len = std::strlen(msgid);
2385 msgid_buf =
new char[len];
2386 std::strncpy(msgid_buf, &msgid[1], --len);
2387 msgid_buf[--len] = 0;
2388 tb.append(msgid_buf);
2393 entity_no.str(std::string());
2394 entity_no << entity << std::flush;
2395 const std::string& s = entity_no.str();
2396 tb.append(s.c_str());
2414 static void gui_decode_mime_entities(Fl_Text_Buffer *tb,
2415 MIMEContent* mimeData,
2418 const char* p = NULL;
2419 const char* q = NULL;
2430 if(NULL == mimeData)
2432 tb->append(S(
"MIME content handling error"));
2437 num = mimeData->parts();
2439 for(i = first; i < num; ++i)
2441 body = mimeData->part(i, &cte, &ct);
2446 last_char = tb->byte_at(tb->length() - 1);
2447 if((
char) 0x0A != last_char) { tb->append(
"\n"); }
2451 if(mimeData->is_multipart())
2453 header = mimeData->part_header(i);
2462 if(ENC_CD_ATTACHMENT == mimeData->type(i)) { attachment = 1; }
2466 tb->append(S(
"Declared as attachment by sender"));
2469 p = gui_create_link_to_entity(msgid, i);
2470 if(NULL == p) { tb->append(
"[Error]"); }
2471 else { tb->append(p); }
2472 std::free((
void*) p);
2480 tb->append(S(
"MIME content type not supported"));
2483 p = gui_create_link_to_entity(msgid, i);
2484 if(NULL == p) { tb->append(
"[Error]"); }
2485 else { tb->append(p); }
2486 std::free((
void*) p);
2494 tb->append(S(
"MIME content decoding failed"));
2499 if(ct->
flags & ENC_CT_FLAG_FLOWED)
2502 ct->
flags & ENC_CT_FLAG_DELSP,
2503 ct->
flags & ENC_CT_FLAG_INSLINE);
2511 if(p != q && p != body) {
enc_free((
void*) p); }
2521 S(
"Conversion from canonical to local form failed"));
2526 if(p != q && p != body) {
enc_free((
void*) p); }
2530 if(p != body) {
enc_free((
void*) p); }
2542 static int gui_check_pathname(
const char* pathname)
2551 fl_message_title(S(
"Warning"));
2552 rv = !fl_choice(
"%s", S(
"Cancel"),
2554 S(
"File exists\nReally continue?"));
2569 static int gui_populate_group_list(
const char* grouplist)
2578 if(NULL != grouplist)
2580 len = std::strlen(grouplist);
2583 buf =
new char[len + (std::size_t) 1];
2586 rv = std::sscanf(&grouplist[pos],
"%s%n", buf, &pos_new);
2587 if (1 != rv || !pos_new) {
break; }
2606 int My_Multi_Browser::handle(
int event)
2610 if(FL_KEYUP == event)
2613 if(Fl::event_key() == FL_Up)
2619 else if(FL_KEYDOWN == event)
2621 if(Fl::event_key() == FL_Enter)
2623 void* sel = selection();
2628 select_only(sel, 1);
2633 else if(Fl::event_key() == 0x20)
2641 if(!res) { res = Fl_Multi_Browser::handle(event); }
2650 int My_Text_Display::handle(
int event)
2663 if(Fl::event_key() == 0x20)
2666 mainWindow->ascrolldown_cb(
true);
2670 else if(!std::strcmp(Fl::event_text(),
"/"))
2672 mainWindow->asearch_cb_i();
2680 if(NULL != mStyleBuffer && 0 != mMaxsize)
2684 pos = xy_to_position(x, y);
2685 style = mStyleBuffer->char_at(pos);
2686 if(NULL != mainWindow)
2688 if(style == mainWindow->hyperlinkStyle)
2691 fl_cursor(FL_CURSOR_HAND);
2693 else { fl_cursor(FL_CURSOR_DEFAULT); }
2703 if(NULL != mStyleBuffer && 0 != mMaxsize)
2705 button = Fl::event_button();
2706 if(FL_LEFT_MOUSE == button)
2711 pos = xy_to_position(x, y);
2712 style = mStyleBuffer->char_at(pos);
2714 if(NULL != mainWindow)
2716 if(style == mainWindow->hyperlinkStyle)
2718 if(FL_PUSH == event) { linkPushed = pos; }
2719 else if(pos == linkPushed)
2724 mainWindow->hyperlinkPosition = pos;
2732 if(FL_RELEASE == event) { linkPushed = -1; }
2742 if(!res) { res = Fl_Text_Display::handle(event); }
2754 int My_Tree::handle(
int event)
2759 if(update_in_progress())
2769 #ifdef FL_ABI_VERSION
2770 # if 10303 <= FL_ABI_VERSION
2772 if(Fl::event_key() == FL_Down)
2774 Fl_Tree_Item* ti = get_item_focus();
2775 if(NULL != ti && NULL == next_visible_item(ti, FL_Down))
2782 # endif // 10303 <= FL_ABI_VERSION
2783 #endif // FL_ABI_VERSION
2785 if(Fl::event_key() == FL_Enter)
2787 #ifdef FL_ABI_VERSION
2788 # if 10301 <= FL_ABI_VERSION
2791 Fl_Tree_Item* ti = first_selected_item();
2792 if(NULL != ti) { deselect(ti); }
2793 select(get_item_focus(), 1);
2794 # endif // 10301 <= FL_ABI_VERSION
2795 #endif // FL_ABI_VERSION
2800 else if(Fl::event_key() == 0x20)
2802 mainWindow->ascrolldown_cb(
true);
2807 else if(!std::strcmp(Fl::event_text(),
"/"))
2809 mainWindow->asearch_cb_i();
2818 res = Fl_Tree::handle(event);
2843 bool MainWindow::stateMachine(
enum mainWindowEvent operation)
2853 case EVENT_SUBSCRIBE:
2854 case EVENT_GL_REFRESH:
2858 case EVENT_SRC_VIEW:
2859 case EVENT_MOTD_VIEW:
2861 mainState = STATE_MUTEX;
2866 mainState = STATE_SERVER1;
2869 case EVENT_G_SELECT:
2871 mainState = STATE_GROUP;
2874 case EVENT_A_PREPARE:
2876 mainState = STATE_NEXT;
2879 case EVENT_SCROLL_NEXT:
2881 mainState = STATE_SCROLL;
2886 mainState = STATE_COMPOSE;
2889 case EVENT_SERVER_EXIT:
2890 case EVENT_G_SELECT_EXIT:
2891 case EVENT_GL_REFRESH_EXIT:
2892 case EVENT_SCROLL_NEXT_EXIT:
2910 case EVENT_SUBSCRIBE_EXIT:
2911 case EVENT_GL_REFRESH_EXIT:
2912 case EVENT_A_VIEW_EXIT:
2913 case EVENT_A_MAAR_EXIT:
2914 case EVENT_A_MAGAR_EXIT:
2915 case EVENT_SRC_VIEW_EXIT:
2916 case EVENT_MOTD_VIEW_EXIT:
2918 mainState = STATE_READY;
2934 case EVENT_GL_PROPOSAL:
2936 mainState = STATE_PROPOSAL;
2939 case EVENT_GL_REFRESH:
2941 mainState = STATE_SERVER2;
2944 case EVENT_SERVER_EXIT:
2946 mainState = STATE_READY;
2962 case EVENT_SERVER_EXIT:
2963 case EVENT_GL_PROPOSAL_EXIT:
2968 case EVENT_GL_REFRESH_EXIT:
2970 mainState = STATE_READY;
2982 case STATE_PROPOSAL:
2986 case EVENT_SERVER_EXIT:
2991 case EVENT_GL_PROPOSAL_EXIT:
2993 mainState = STATE_READY;
2996 case EVENT_GL_REFRESH:
2998 mainState = STATE_SERVER2;
3014 case EVENT_G_SELECT_EXIT:
3015 case EVENT_AT_REFRESH:
3020 case EVENT_AT_REFRESH_EXIT:
3022 mainState = STATE_READY;
3038 case EVENT_A_PREPARE:
3040 mainState = STATE_NEXT;
3043 case EVENT_SCROLL_NEXT_EXIT:
3045 mainState = STATE_READY;
3061 case EVENT_A_SELECT:
3062 case EVENT_SCROLL_NEXT_EXIT:
3067 case EVENT_A_SELECT_EXIT:
3069 mainState = STATE_READY;
3087 mainState = STATE_POST;
3090 case EVENT_COMPOSE_EXIT:
3092 mainState = STATE_READY;
3108 case EVENT_POST_EXIT:
3110 mainState = STATE_COMPOSE;
3125 PRINT_ERROR(
"Invalid state detected by main window state machine");
3126 mainState = STATE_READY;
3139 void MainWindow::exit_cb_i(
void)
3142 if(Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape)
3155 void MainWindow::print_cb_i(
void)
3157 const Fl_Font font = FL_COURIER;
3158 const Fl_Fontsize fontsize = 14;
3159 const char line[] =
"________________________________________"
3160 "________________________________________";
3161 int old_scrollbar_size = Fl::scrollbar_size();
3166 Fl_Text_Display canvas(0, 0, 100, 100);
3169 int frompage, topage;
3180 int current_line = 1;
3183 if(NULL == currentGroup)
3185 SC(
"Do not use non-ASCII for the translation of this item")
3186 fl_message_title(S("Error"));
3187 fl_alert("%s", S("No group selected"));
3189 else if(NULL == currentArticleHE)
3191 SC(
"Do not use non-ASCII for the translation of this item")
3192 fl_message_title(S("Error"));
3193 fl_alert("%s", S("No article selected"));
3198 fl_font(font, fontsize);
3199 fl_measure(line, w = 0, lh = 0);
3200 if(0 >= w || 0 >= lh) { res = -1; }
3201 else { h = (int) std::ceil((
double) w * std::sqrt(2.0)); }
3205 p = text->buffer()->text();
3206 if(NULL != p) { tb.text(p); }
3207 std::free((
void*) p);
3208 lines = tb.count_lines(0, tb.length());
3211 printf(
"%s: %sPrinting article with %d lines\n",
3214 if (0 >= lines) { res = -1; }
3219 p = currentStyle->text();
3220 if(NULL != p) { sb.text(p); }
3221 std::free((
void*) p);
3225 canvas.box(FL_NO_BOX);
3226 canvas.textfont(font);
3227 canvas.textsize(fontsize);
3228 canvas.resize(0, 0, w, h);
3230 canvas.highlight_data(&sb, styles, styles_len,
'A', NULL, NULL);
3233 while(canvas.position_to_xy(i, &x, &y))
3235 if(!canvas.move_down()) {
break; }
3236 i = canvas.insert_position();
3244 if(0 >= lpp) { res = -1; }
3248 printf(
"%s: %sPrinting %d lines per page\n",
3254 for(i = 0; i < lpp; ++i) { tb.append(
"\n"); }
3255 pages = lines / lpp;
3256 if(lines % lpp) { ++pages; }
3257 if(1 > pages) { res = -1; }
3261 printf(
"%s: %sPrinting %d pages\n",
3268 res = printer.start_job(pages, &frompage, &topage);
3272 Fl::scrollbar_size(0);
3273 for(i = 1; i <= pages; ++i)
3276 canvas.scroll(current_line, 0);
3278 if(i >= frompage && i <= topage)
3281 res = printer.start_page();
3284 res = printer.printable_rect(&pw, &ph);
3287 sf = (float) pw / (
float) w;
3288 tmp = (float) ph / (
float) h;
3289 if(std::fabs(tmp) < std::fabs(sf)) { sf = tmp; }
3293 printer.print_widget((Fl_Widget*) &canvas);
3295 rv = printer.end_page();
3296 if(!res) { res = rv; }
3304 current_line += lpp;
3308 Fl::scrollbar_size(old_scrollbar_size);
3315 SC(
"Do not use non-ASCII for the translation of this item")
3316 fl_message_title(S("Error"));
3317 fl_alert("%s", S("Printing failed or aborted"));
3325 void MainWindow::asave_cb_i(
void)
3327 const char* pathname;
3330 if(NULL == currentGroup)
3332 SC(
"Do not use non-ASCII for the translation of this item")
3333 fl_message_title(S("Error"));
3334 fl_alert("%s", S("No group selected"));
3336 else if(NULL == currentArticleHE)
3338 SC(
"Do not use non-ASCII for the translation of this item")
3339 fl_message_title(S("Error"));
3340 fl_alert("%s", S("No article selected"));
3344 SC(
"Do not use characters for the translation that cannot be")
3345 SC("converted to the ISO 8859-1 character set for this item.")
3346 SC("Leave the original
string in place if in doubt.")
3347 const
char* title = S("Save article");
3350 fl_file_chooser_ok_label(S("Save"));
3351 if(NULL != suggested_pathname)
3353 pathname = fl_file_chooser(title,
"*", suggested_pathname, 0);
3354 if(NULL != pathname)
3357 rv = gui_check_pathname(pathname);
3360 rv = gui_save_to_file(pathname, currentArticle);
3363 SC(
"Do not use non-ASCII for the translation of this item")
3364 fl_message_title(S("Error"));
3365 fl_alert("%s", S("Operation failed"));
3378 void MainWindow::asearch_cb_i(
void)
3380 SearchWindow* sw = NULL;
3384 std::size_t tmp, tmp2;
3386 int start, end, len;
3387 int sel_start, sel_end;
3389 SC("Do not use characters for the translation that cannot be converted to")
3390 SC("the ISO 8859-1 character set for this item.")
3391 SC("Leave the original
string in place if in doubt.")
3392 const
char* titleString = S("Search in article");
3395 if(NULL == currentArticleHE)
3397 SC(
"Do not use non-ASCII for the translation of this item")
3398 fl_message_title(S("Error"));
3399 fl_alert("%s", S("No article selected"));
3404 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3409 title = gui_utf8_iso(titleString);
3412 sw =
new SearchWindow(title, ¤tSearchString);
3415 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3416 sw =
new SearchWindow(titleString, ¤tSearchString);
3417 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3423 sw->default_cursor(FL_CURSOR_DEFAULT);
3426 while(!sw->finished) { Fl::wait(); }
3427 sw->default_cursor(FL_CURSOR_WAIT);
3428 result = sw->finished;
3432 currentArticle->unhighlight();
3436 UI_STATUS(S(
"Search cancelled, reset start position."));
3437 currentSearchPosition = 0;
3442 UI_STATUS(S(
"Searching in article ..."));
3448 p = currentArticle->text();
3449 found = !enc_uc_search(p, (
size_t) currentSearchPosition,
3450 currentSearchString, &tmp, &tmp2);
3451 if((std::size_t) INT_MAX <= tmp) { found_pos = INT_MAX; }
3452 else { found_pos = (int) tmp; }
3453 if((std::size_t) INT_MAX <= tmp2) { len = INT_MAX; }
3454 else { len = (int) tmp2; }
3455 std::free((
void*) p);
3460 found = currentArticle->search_forward(currentSearchPosition,
3461 currentSearchString,
3464 len = (int) std::strlen(currentSearchString);
3470 if(INT_MAX - start < len) { len = INT_MAX - start; }
3472 currentSearchPosition = end;
3473 currentArticle->highlight(start, end);
3474 UI_STATUS(S(
"Search string found and marked, position stored."));
3477 if(currentArticle->highlight_position(&sel_start, &sel_end))
3480 text->insert_position(0);
3481 text->show_insert_position();
3482 text->insert_position(sel_end);
3483 text->show_insert_position();
3488 UI_STATUS(S(
"Search string not found, reset start position."));
3490 currentSearchPosition = 0;
3497 if(NULL != sw) {
delete sw; }
3506 void MainWindow::calculatePercent(std::size_t current, std::size_t complete)
3508 std::ostringstream percentString;
3510 progress_percent_value = 100.0;
3511 progress_percent_label[0] =
'1';
3512 progress_percent_label[1] =
'0';
3513 progress_percent_label[2] =
'0';
3514 progress_percent_label[3] =
'%';
3515 if(complete && (current < complete))
3517 progress_percent_value = (float) current / (
float) complete;
3518 progress_percent_value *= (float) 100.0;
3519 percentString.precision(0);
3520 percentString << std::fixed << progress_percent_value <<
"%"
3532 const std::string& ps = percentString.str();
3534 std::strncpy(progress_percent_label, ps.c_str(), (std::size_t) 4);
3537 progress_percent_label[4] = 0;
3544 void MainWindow::config_cb_i(
void)
3547 SC("Do not use characters for the translation that cannot be converted to")
3548 SC("the ISO 8859-1 character set for this item.")
3549 SC("Leave the original
string in place if in doubt.")
3550 const
char* titleString = S("Configuration");
3554 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3559 title = gui_utf8_iso(titleString);
3562 new MiscCfgWindow(title);
3565 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3566 new MiscCfgWindow(titleString);
3567 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3574 void MainWindow::identity_cb_i(
void)
3577 SC("Do not use characters for the translation that cannot be converted to")
3578 SC("the ISO 8859-1 character set for this item.")
3579 SC("Leave the original
string in place if in doubt.")
3580 const
char* titleString = S("Identity configuration");
3584 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3589 title = gui_utf8_iso(titleString);
3592 new IdentityCfgWindow(title);
3595 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3596 new IdentityCfgWindow(titleString);
3597 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3604 void MainWindow::mid_search_cb_i(
void)
3607 SC("Do not use characters for the translation that cannot be converted to")
3608 SC("the ISO 8859-1 character set for this item.")
3609 SC("Leave the original
string in place if in doubt.")
3610 const
char* titleString = S("Message-ID search");
3614 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3619 title = gui_utf8_iso(titleString);
3622 new MIDSearchWindow(title);
3625 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3626 new MIDSearchWindow(titleString);
3627 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3634 void MainWindow::about_cb_i(
void)
3636 std::ostringstream titleString;
3640 SC("Do not use characters for the translation that cannot be converted to")
3641 SC("the ISO 8859-1 character set for this item.")
3642 SC("Leave the original
string in place if in doubt.")
3643 titleString << S("About") << " " << CFG_NAME << std::flush;
3655 const std::
string& ts = titleString.str();
3656 const std::
string& as = aboutString.str();
3659 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3664 title = gui_utf8_iso(ts.c_str());
3667 fl_message_title(title);
3670 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3671 fl_message_title(ts.c_str());
3672 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3675 fl_message(
"%s", as.c_str());
3682 void MainWindow::bug_cb_i()
3684 std::ostringstream subjectString;
3685 std::ostringstream configString;
3686 std::ostringstream contentString;
3687 std::ostringstream titleString;
3694 configString <<
"Configuration:" <<
"\n"
3695 << CFG_NAME <<
" " << CFG_VERSION
3696 <<
" " <<
"for" <<
" " << CFG_OS <<
"\n"
3698 <<
"(This is a modified version!)" <<
"\n"
3699 #endif // CFG_MODIFIED
3700 <<
"Unicode version: " << UC_VERSION <<
"\n"
3702 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3703 <<
"Enabled" <<
"\n"
3704 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3705 <<
"Disabled" <<
"\n"
3706 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3707 <<
"Message locale: " <<
nls_loc <<
"\n"
3710 <<
"Available" <<
"\n"
3711 # if CFG_USE_OPENSSL_API_1_1
3712 <<
"Compiled for OpenSSL API 1.1" <<
"\n"
3713 # endif // !CFG_USE_OPENSSL_API_1_1
3714 #else // CFG_USE_TLS
3715 <<
"Not available" <<
"\n"
3716 #endif // CFG_USE_TLS
3717 <<
"Compiled for: FLTK " << FL_MAJOR_VERSION <<
"."
3718 << FL_MINOR_VERSION <<
"." << FL_PATCH_VERSION <<
"\n"
3719 #if CFG_CMPR_DISABLE
3720 <<
"Compression disabled" <<
"\n"
3721 #else // CFG_CMPR_DISABLE
3722 <<
"Compression available"
3725 # endif // CFG_USE_ZLIB
3727 #endif // CFG_CMPR_DISABLE
3728 <<
"Build: " << BDATE
3730 <<
"Problem description (in english):" <<
"\n\n"
3732 subjectString <<
"[" << CFG_NAME <<
"] "
3733 <<
"Bug report (...)"
3735 contentString << S(
"Report bug to:") <<
"\n"
3738 << S(
"Use the following subject line and replace")
3739 <<
" '...' " << S(
"with a summary") <<
":\n"
3740 << subjectString.str() <<
"\n\n"
3741 << S(
"Use the following skeleton:") <<
"\n"
3742 <<
"------------------------------------------------------\n"
3743 << configString.str()
3744 <<
"------------------------------------------------------\n"
3749 SC("Do not use characters for the translation that cannot be converted to")
3750 SC("the ISO 8859-1 character set for this item.")
3751 SC("Leave the original
string in place if in doubt.")
3752 titleString << S("Bug report") << std::flush;
3764 const std::
string& ts = titleString.str();
3765 const std::
string& cs = contentString.str();
3766 const std::
string&
config = configString.str();
3767 const std::
string& subject = subjectString.str();
3770 len = std::strlen(CFG_MAINTAINER);
3771 p = new
char[++len];
3772 std::strncpy(p, CFG_MAINTAINER, len);
3773 p[len - (
size_t) 1] = 0;
3775 q = std::strstr(p, "mailto:");
3791 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3796 title = gui_utf8_iso(ts.c_str());
3800 new BugreportWindow(title, cs.c_str());
3804 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3806 new BugreportWindow(ts.c_str(), cs.c_str());
3807 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3815 void MainWindow::license_cb_i(
void)
3817 std::ostringstream titleString;
3821 SC("Do not use characters for the translation that cannot be converted to")
3822 SC("the ISO 8859-1 character set for this item.")
3823 SC("Leave the original
string in place if in doubt.")
3824 titleString << S("License") << std::flush;
3836 const std::
string& ts = titleString.str();
3839 #if CFG_USE_XSI && !CFG_NLS_DISABLE
3844 title = gui_utf8_iso(ts.c_str());
3848 new LicenseWindow(title);
3852 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
3854 new LicenseWindow(ts.c_str());
3855 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
3862 void MainWindow::console_cb_i(
void)
3864 if(NULL == protocolConsole)
3867 SC("Do not use characters for the translation that cannot be converted to")
3868 SC("the ISO 8859-1 character set for this item.")
3869 SC("Leave the original
string in place if in doubt.")
3870 protocolConsole = new ProtocolConsole(S("Protocol console"));
3879 void MainWindow::rot13_cb_i(
void)
3882 Fl_Text_Buffer* newdata =
new Fl_Text_Buffer(0, 0);
3884 if(NULL == currentGroup)
3886 SC(
"Do not use non-ASCII for the translation of this item")
3887 fl_message_title(S("Error"));
3888 fl_alert("%s", S("No group selected"));
3890 else if(NULL == currentArticleHE)
3892 SC(
"Do not use non-ASCII for the translation of this item")
3893 fl_message_title(S("Error"));
3894 fl_alert("%s", S("No article selected"));
3909 olddata = currentArticle->text();
3913 newdata->text(olddata);
3914 articleUpdate(newdata);
3916 std::free((
void*) olddata);
3927 void MainWindow::msau_cb_i(
void)
3932 if(NULL == currentGroup)
3934 SC(
"Do not use non-ASCII for the translation of this item")
3935 fl_message_title(S("Error"));
3936 fl_alert("%s", S("No group selected"));
3938 else if(NULL == currentArticleHE)
3940 SC(
"Do not use non-ASCII for the translation of this item")
3941 fl_message_title(S("Error"));
3942 fl_alert("%s", S("No article selected"));
3946 ti = articleTree->first_selected_item();
3953 ti->labelfont(FL_HELVETICA_BOLD);
3960 ti->labelfont(FL_HELVETICA);
3964 articleTree->redraw();
3965 groupListUpdateEntry(group_list_index);
3973 void MainWindow::mssar(Fl_Tree_Item* ti)
3984 ti->labelfont(FL_HELVETICA);
3988 for(i = 0; ti->children() > i; ++i)
3990 mssar(ti->child(i));
3995 void MainWindow::mssar_cb_i(
void)
3999 if(NULL == currentGroup)
4001 SC(
"Do not use non-ASCII for the translation of this item")
4002 fl_message_title(S("Error"));
4003 fl_alert("%s", S("No group selected"));
4007 ti = articleTree->first_selected_item();
4008 if(NULL == currentArticleHE || NULL == ti)
4010 SC(
"Do not use non-ASCII for the translation of this item")
4011 fl_message_title(S("Error"));
4012 fl_alert("%s", S("No article selected"));
4024 ti = articleTree->first_selected_item();
4027 articleTree->close(ti);
4031 groupListUpdateEntry(group_list_index);
4032 UI_STATUS(S(
"Marked all articles in subthread read."));
4041 void MainWindow::maar_cb_i(
void)
4046 if(stateMachine(EVENT_A_MAAR))
4048 if(NULL != currentGroup)
4051 for(ti = articleTree->first()->next(); ti; ti = articleTree->next(ti))
4053 ti->labelfont(FL_HELVETICA);
4055 articleTree->redraw();
4059 if(currentGroup->lwm && currentGroup->hwm >= currentGroup->lwm)
4062 for(a = currentGroup->hwm; a >= currentGroup->lwm; --a)
4069 groupListUpdateEntry(group_list_index);
4070 UI_STATUS(S(
"Marked all articles in group read."));
4073 if(!stateMachine(EVENT_A_MAAR_EXIT))
4075 PRINT_ERROR(
"Error in main window state machine");
4084 void MainWindow::magar_cb_i(
void)
4092 if(stateMachine(EVENT_A_MAGAR))
4095 fl_message_title(S(
"Warning"));
4096 rv = fl_choice(
"%s", S(
"No"),
4098 S(
"Really mark all groups read?"));
4102 if(NULL != currentGroup)
4104 for(ti = articleTree->first()->next(); ti;
4105 ti = articleTree->next(ti))
4107 ti->labelfont(FL_HELVETICA);
4109 articleTree->redraw();
4113 for(i = 0; group_num > i; ++i)
4116 g = &subscribedGroups[i];
4117 if(g->lwm && g->hwm >= g->lwm)
4120 for(a = g->hwm; a >= g->lwm; --a)
4126 groupListUpdateEntry(i);
4128 UI_STATUS(S(
"Marked all articles in all groups read."));
4131 if(!stateMachine(EVENT_A_MAGAR_EXIT))
4133 PRINT_ERROR(
"Error in main window state machine");
4142 void MainWindow::aselect_cb_i(
void)
4144 Fl_Tree_Item* ti = articleTree->callback_item();
4146 switch(articleTree->callback_reason())
4148 case FL_TREE_REASON_OPENED:
4155 ti->labelfont(FL_HELVETICA);
4158 scrollTree(UI_SCROLL_TOP, ti);
4161 case FL_TREE_REASON_CLOSED:
4164 if(checkTreeBranchForUnread(ti))
4167 ti->labelfont(FL_HELVETICA_BOLD);
4171 case FL_TREE_REASON_SELECTED:
4176 if(NULL == ti->user_data())
4178 PRINT_ERROR(
"No data associated with selected article item");
4183 if(stateMachine(EVENT_A_PREPARE))
4186 if(ti->is_open() || !checkTreeBranchForUnread(ti))
4190 ti->labelfont(FL_HELVETICA);
4193 lastArticleHE = currentArticleHE;
4197 articleSelect(UI_CB_START);
4199 scrollTree(UI_SCROLL_MIDDLE, ti);
4202 articleTree->store_current(ti);
4207 articleTree->select_former();
4224 void MainWindow::stripAngleAddress(
char* from)
4232 p = std::strrchr(from, (
int)
'<');
4234 q = std::strrchr(from, (
int)
'>');
4235 if(NULL != p && NULL != q && q > p + 1)
4238 for(i = 0; i < (std::size_t) (p - from); ++i)
4240 if(
' ' != from[i]) { strip =
true;
break; }
4245 if(
' ' == *(p - 1)) { --p; }
4252 std::memmove((
void*) from, (
void*) (p + 1), (std::size_t) (q - p));
4261 void MainWindow::sendEmail(
void)
4263 const char* recipient;
4264 const char* subject;
4265 const char* body = NULL;
4282 if(NULL == currentGroup)
4284 SC(
"Do not use non-ASCII for the translation of this item")
4285 fl_message_title(S("Error"));
4286 fl_alert("%s", S("No group selected"));
4288 else if(NULL == currentArticleHE)
4290 SC(
"Do not use non-ASCII for the translation of this item")
4291 fl_message_title(S("Error"));
4292 fl_alert("%s", S("No article selected"));
4296 recipient = currentArticleHE->header->reply2;
4297 if(NULL == recipient) { recipient = currentArticleHE->header->from; }
4298 if(NULL == recipient)
4308 if(NULL == recipient) { invalid = 1; }
4312 p = std::strrchr(recipient, (
int)
'.');
4316 if(!std::strcmp(p,
".test")) { invalid = 1; }
4317 if(!std::strcmp(p,
".example")) { invalid = 1; }
4318 if(!std::strcmp(p,
".invalid")) { invalid = 1; }
4319 if(!std::strcmp(p,
".localhost")) { invalid = 1; }
4324 hdr = currentArticleHE->header;
4325 t = currentArticle->text();
4329 while(
'_' != t[i++]);
4330 while(
'|' != t[i++]);
4331 while(
'|' != t[i++]);
4339 sig_delim = std::strstr(r,
"\n-- \n");
4340 if(NULL == sig_delim) {
break; }
4341 else { sig = r = &sig_delim[1]; }
4343 if(NULL != sig) { sig[0] = 0; }
4345 len = std::strlen(hdr->
from);
4346 from =
new char[++len];
4348 stripAngleAddress(
from);
4356 subject = currentArticleHE->header->subject;
4357 s =
new char[std::strlen(
subject) + (std::size_t) 5];
4358 std::strcpy(s,
"Re: ");
4359 std::strcat(s, gui_check_re_prefix(
subject));
4361 q = std::strstr(s,
"(was:");
4366 if(std::strchr(q, (
int)
')'))
4369 if(
' ' == *(--q)) { *q = 0; }
4378 if(std::strchr(
subject, 0x27)) { warn = 1; }
4380 if(!warn && NULL != body)
4384 if(std::strchr(body, 0x27)) { warn = 1; }
4388 SC(
"Do not use non-ASCII for the translation of this item")
4389 fl_message_title(S("Note"));
4391 S("APOSTROPHE converted to\nRIGHT SINGLE QUOTATION MARK"));
4397 SC(
"Do not use non-ASCII for the translation of this item")
4398 fl_message_title(S("Error"));
4399 fl_alert("%s", S("Starting e-mail client failed"));
4402 std::free((
void*) body);
4403 std::free((
void*) t);
4409 SC(
"Do not use non-ASCII for the translation of this item")
4410 fl_message_title(S("Error"));
4411 fl_alert("%s", S("Invalid e-mail address"));
4422 void MainWindow::ascrolldown_cb(
bool scroll)
4441 if(stateMachine(EVENT_SCROLL_NEXT))
4447 if(NULL != currentArticle && text->buffer() == currentArticle)
4449 r = text->count_lines(0, text->buffer()->length(),
true);
4452 for(i = 0; i < r; ++i)
4454 if(text->position_to_xy(p, &x, &y))
4456 if(0 > f) { l = f = i; }
4459 p = text->skip_lines(p, 1,
true);
4461 if(0 > f) { f = 0; l = 0; }
4467 std::printf(
"-----------------------------\n");
4468 std::printf(
"Rows : %d\n", r);
4469 std::printf(
"Current row : %d\n", currentLine);
4470 std::printf(
"First in view: %d\n", f);
4471 std::printf(
"Last in view : %d\n", l);
4472 std::printf(
"Rows in view : %d\n", riv);
4480 scrollto = currentLine + riv - 2;
4481 if(scrollto < r - 1)
4484 text->scroll(scrollto + 1, 0);
4496 fi = articleTree->first_selected_item();
4499 fi = articleTree->first();
4500 if(fi == articleTree->root()) { fi = articleTree->next(fi); }
4503 if(NULL != fi && NULL == fi->user_data()) { fi = NULL; }
4512 while(articleTree->root() != oi)
4514 if(!articleTree->open(oi)) { articleTree->open(oi, 1); }
4515 for(i = 0; i < articleTree->root()->children(); ++i)
4517 if(articleTree->root()->child(i) == oi)
4523 if(abort) {
break; }
4524 oi = articleTree->prev(oi);
4527 articleTree->deselect(fi, 0);
4528 articleTree->set_item_focus(ti);
4529 articleTree->select(ti, 1);
4533 ti = articleTree->next(ti);
4534 if(NULL == ti && !wrap)
4538 ti = articleTree->first();
4539 if(ti == articleTree->root()) { ti = articleTree->next(ti); }
4543 if(!stateMachine(EVENT_SCROLL_NEXT_EXIT))
4545 PRINT_ERROR(
"Error in main window state machine");
4561 void MainWindow::updateServer(
int action)
4564 SC("Do not use characters for the translation that cannot be converted to")
4565 SC("the ISO 8859-1 character set for this item.")
4566 SC("Leave the original
string in place if in doubt.")
4567 const
char* titleString = S("Server configuration");
4571 ServerCfgWindow* scw = NULL;
4572 ServerConfig* sc = NULL;
4573 const
char* user = NULL;
4574 const
char* pass = NULL;
4577 if(UI_CB_START == action)
4580 if(!stateMachine(EVENT_SERVER)) { rv = 1; }
4585 SC(
"Do not use non-ASCII for the translation of this item")
4586 fl_message_title(S("Note"));
4587 SC("Line breaks are inserted with \n")
4589 S("Warning:\nGroup states are lost if the server is changed."));
4592 sc = new ServerConfig;
4599 #if CFG_USE_XSI && !CFG_NLS_DISABLE
4604 title = gui_utf8_iso(titleString);
4607 scw =
new ServerCfgWindow(sc, title);
4610 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
4611 scw =
new ServerCfgWindow(sc, titleString);
4612 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
4616 PRINT_ERROR(
"Fatal error while creating server config window");
4621 if(0 < scw->process())
4624 UI_STATUS(S(
"Update server configuration ..."));
4643 else { cancel = 1; }
4664 UI_STATUS(S(
"Updating server configuration failed."));
4681 if(UI_AUTH_USER == sc->auth)
4687 SC(
"Do not use non-ASCII for the translation of this item")
4688 fl_message_title(S("Note"));
4689 rv = fl_choice("%s", S("No"),
4691 S("Store the password
from the subsequent request?"));
4702 SC(
"Do not use non-ASCII for the translation of this item")
4703 fl_message_title(S("Warning"));
4704 fl_alert("%s", S("Empty password is not supported"));
4715 SC(
"Do not use non-ASCII for the translation of this item")
4716 fl_message_title(S("Note"));
4717 rv = fl_choice("%s", S("No"),
4719 S("Ask server for group subscription proposals?"));
4723 groupListGetProposal(UI_CB_START);
4727 UI_STATUS(S(
"No groups subscribed yet."));
4735 groupListRefresh(UI_CB_START);
4738 if(NULL != sc) {
delete sc; }
4739 if(!stateMachine(EVENT_SERVER_EXIT))
4741 PRINT_ERROR(
"Error in main window state machine");
4751 void MainWindow::groupSubscribe(
int action)
4754 std::size_t labelcount;
4756 std::size_t i, ii, j;
4761 int fake_empty_response = 0;
4764 if(UI_CB_START == action)
4766 if(!stateMachine(EVENT_SUBSCRIBE)) { rv = 1; }
4770 UI_STATUS(S(
"Receiving group list ..."));
4784 if(!rv && UI_CB_CONTINUE == action)
4791 UI_STATUS(S(
"Receiving group labels ..."));
4795 if(0 > rv) { fake_empty_response = 1; }
4798 if(0 > rv && UI_CB_FINISH == action) { fake_empty_response = 1; }
4800 if (fake_empty_response)
4816 UI_STATUS(S(
"Downloading group information failed."));
4826 UI_STATUS(S(
"Group information received."));
4829 SC("Do not use characters for the translation that cannot be")
4830 SC("converted to the ISO 8859-1 character set for this item.")
4831 SC("Leave the original
string in place if in doubt.")
4832 subscribeWindow = new SubscribeWindow(S("Subscribe"),
4836 UI_STATUS(S("Process group information ..."));
4837 subscribeWindow->hide();
4839 for(i = 0; i < groupcount; ++i)
4846 name = grouplist[i].name;
4847 num = grouplist[i].eac;
4849 for(j = 0; j < labelcount; ++j)
4851 if(!strcmp(labels[j].name, name))
4858 label = labels[j].label;
4863 PRINT_ERROR(
"Invalid encoding of group description");
4865 if(NULL != label) { free_label = 1; }
4872 do {
if(
'.' == name[ii]) { name[ii] =
'/'; } }
4874 subscribeWindow->add(name, num, label);
4875 if(free_label) {
core_free((
void*) label); }
4880 subscribeWindow->collapseAll();
4881 subscribeWindow->show();
4882 UI_STATUS(S(
"Group information processed."));
4888 if(!stateMachine(EVENT_SUBSCRIBE_EXIT))
4890 PRINT_ERROR(
"Error in main window state machine");
4905 if(lwm && hwm && hwm >= lwm)
4914 for(i = info->
last; i >= info->
first; --i)
4916 if(i >= lwm && i <= hwm) {
if(res) { --res; } }
4929 void MainWindow::groupListUpdateEntry(std::size_t i)
4931 std::ostringstream groupString;
4937 if((std::size_t) 500 >= i)
4940 groupCAC(&subscribedGroups[i]);
4943 eac = subscribedGroups[i].eac;
4944 ur = groupGetUnreadNo(subscribedGroups[i].lwm, subscribedGroups[i].hwm,
4945 group_list[i].info);
4947 if(ur) { fcs =
"@b"; }
else { fcs =
"@."; }
4948 groupString << fcs << group_list[i].
name
4949 <<
" (" << ur <<
" / " << eac <<
")" << std::flush;
4960 const std::string& gs = groupString.str();
4963 if(++i > (std::size_t) groupList->size())
4966 groupList->add(gs.c_str(), NULL);
4971 groupList->text((
int) i, gs.c_str());
4980 int MainWindow::groupStateMerge(
void)
4990 SC(
"Do not use non-ASCII for the translation of this item")
4991 fl_message_title(S("Error"));
4992 fl_alert("%s", S("Exporting group states failed"));
5007 void MainWindow::groupListGetProposal(
int action)
5010 char* grouplist_raw;
5013 if(UI_CB_START == action)
5016 if(!stateMachine(EVENT_GL_PROPOSAL)) { rv = 1; }
5020 UI_STATUS(S(
"Get group subscription proposals ..."));
5039 UI_STATUS(S(
"Receiving proposed groups failed."));
5048 rv = gui_populate_group_list(grouplist_raw);
5051 PRINT_ERROR(
"Updating list of subscribed groups failed");
5055 groupListRefresh(UI_CB_START);
5057 if(!stateMachine(EVENT_GL_PROPOSAL_EXIT))
5059 PRINT_ERROR(
"Error in main window state machine");
5069 void MainWindow::groupListRefresh(
int action)
5077 if(UI_CB_START == action)
5080 if(!stateMachine(EVENT_GL_REFRESH)) { rv = 1; }
5083 rv = groupStateMerge();
5087 UI_STATUS(S(
"Refreshing subscribed groups ..."));
5089 for(g = 1; groupList->size() >= g; ++g)
5091 if(groupList->selected(g)) { sg = g;
break; }
5093 groupRefresh_cb_state = sg;
5095 UI_CB_COOKIE_GROUPINFO1);
5108 if(!rv && UI_CB_CONTINUE == action)
5111 if(NULL != subscribedGroups)
5120 for(i = 0; i < group_num; ++i) { groupListUpdateEntry(i); }
5122 if(group_num && NULL != currentGroup)
5125 UI_CB_COOKIE_GROUPINFO2);
5130 if(!rv && UI_CB_FINISH == action)
5147 currentGroup = NULL;
5148 UI_STATUS(S(
"Refreshing subscribed groups failed."));
5152 groupList->deselect();
5153 if(!group_num || unsub)
5158 currentGroup = NULL;
5162 if (0 == groupRefresh_cb_state)
5164 if (0 != groupList->size())
5166 groupList->select(1, 0);
5168 groupList->redraw();
5174 groupList->select(groupRefresh_cb_state);
5175 groupList->middleline(groupRefresh_cb_state);
5179 UI_STATUS(S(
"Subscribed groups refreshed."));
5183 if(!stateMachine(EVENT_GL_REFRESH_EXIT))
5185 PRINT_ERROR(
"Error in main window state machine");
5195 void MainWindow::groupSelect(
int action,
int index)
5199 if(UI_CB_START == action)
5201 if(!index || !stateMachine(EVENT_G_SELECT))
5203 if(NULL != currentGroup)
5206 if((std::size_t) INT_MAX > group_list_index)
5208 groupList->deselect();
5209 groupList->select((
int) group_list_index + 1);
5223 if((std::size_t) INT_MAX > group_list_index)
5225 group_old = (int) group_list_index + 1;
5228 group_list_index = (std::size_t) index;
5229 if(--group_list_index < group_num)
5231 UI_STATUS(S(
"Set new current group ..."));
5233 groupSelect_cb_state = groupList->value();
5235 UI_CB_COOKIE_GROUP);
5255 UI_STATUS(S(
"Setting new current group failed."));
5260 groupList->select(group_new, 0);
5261 groupList->make_visible(group_new);
5265 group_list_index = group_old - 1;
5266 groupList->deselect();
5267 groupList->select(group_old);
5268 groupList->make_visible(group_old);
5270 if(stateMachine(EVENT_AT_REFRESH))
5272 if(!stateMachine(EVENT_AT_REFRESH_EXIT))
5274 PRINT_ERROR(
"Error in main window state machine");
5286 groupList->make_visible(group_new);
5288 groupCAC(currentGroup);
5292 lastArticleHE = NULL;
5293 currentArticleHE = NULL;
5294 updateArticleTree(UI_CB_START);
5296 if(!stateMachine(EVENT_G_SELECT_EXIT))
5298 PRINT_ERROR(
"Error in main window state machine");
5312 if(NULL != g && 0 < i--)
5315 if(g->hwm >= g->lwm && g->eac)
5320 if(g->hwm - g->lwm > diff) { g->lwm = g->hwm - diff; }
5329 void MainWindow::clearTree(
void)
5335 articleTree->item_labelfont(FL_HELVETICA);
5336 articleTree->clear();
5337 ti = articleTree->add(S(
"No articles"));
5338 if(NULL != ti) { ti->deactivate(); }
5339 articleTree->redraw();
5342 lastArticleHE = NULL;
5344 currentArticleHE = NULL;
5346 if(startup) { startup =
false; }
5349 tb =
new Fl_Text_Buffer(0, 0);
5367 void MainWindow::scrollTree(ui_scroll position, Fl_Tree_Item* ti)
5369 bool old_tree_widget =
true;
5372 #ifdef FL_ABI_VERSION
5373 # if 10303 <= FL_ABI_VERSION
5375 articleTree->hposition(0);
5376 articleTree->calc_tree();
5377 articleTree->hposition(0);
5378 old_tree_widget =
false;
5379 # endif // 10303 <= FL_ABI_VERSION
5380 #endif // FL_ABI_VERSION
5384 articleTree->vposition(0);
5386 articleTree->redraw();
5387 articleTree->not_drawn();
5389 while(!articleTree->drawn()) { Fl::wait(0.10); }
5394 #ifdef FL_ABI_VERSION
5395 # if 10303 <= FL_ABI_VERSION
5397 gui_set_default_font();
5399 int xmax = ti->draw_item_content(0);
5400 int scroll = xmax - (articleTree->x() + articleTree->w());
5403 if(articleTree->is_vscroll_visible())
5406 int w_sb = articleTree->scrollbar_size();
5407 if (0 == w_sb) { w_sb = Fl::scrollbar_size(); }
5413 int left = ti->x() - articleTree->x();
5419 articleTree->hposition(scroll);
5422 # endif // 10303 <= FL_ABI_VERSION
5423 #endif // FL_ABI_VERSION
5430 articleTree->show_item_top(ti);
5433 case UI_SCROLL_MIDDLE:
5435 articleTree->show_item_middle(ti);
5438 case UI_SCROLL_BOTTOM:
5440 articleTree->show_item_bottom(ti);
5443 case UI_SCROLL_NONE:
5451 articleTree->redraw();
5459 bool MainWindow::checkTreeBranchForUnread(Fl_Tree_Item* ti)
5468 for(i = 0; i < c; ++i)
5471 if(FL_HELVETICA_BOLD == ti->child(i)->labelfont()) { res =
true; }
5475 if(checkTreeBranchForUnread(ti->child(i))) { res =
true; }
5477 if(
true == res) {
break; }
5489 bool MainWindow::checkTreeBranchForItem(Fl_Tree_Item* ti, Fl_Tree_Item* sti)
5498 for(i = 0; i < c; ++i)
5501 if(ti->child(i) == sti) { res =
true; }
5505 if(checkTreeBranchForItem(ti->child(i), sti)) { res =
true; }
5507 if(
true == res) {
break; }
5536 Fl_Tree_Item* MainWindow::addTreeNodes(Fl_Tree_Item* cti,
5539 static const char t[] =
" | ";
5540 std::size_t t_len =
sizeof(t);
5551 unsigned long int l_raw;
5553 #endif // USE_LINE_COUNT
5554 #if USE_ARTICLE_NUMBER
5556 #endif // USE_ARTICLE_NUMBER
5557 std::size_t l_len = 0;
5558 std::size_t a_len = 0;
5559 Fl_Tree_Item* res = NULL;
5560 Fl_Tree_Item* tmp = NULL;
5561 Fl_Tree_Item* nti = NULL;
5569 bool child_of_root_node =
false;
5584 articleTree->item_labelfgcolor(FL_FOREGROUND_COLOR);
5587 articleTree->item_labelfont(FL_HELVETICA_BOLD);
5590 if(articleTree->root() == cti) { child_of_root_node =
true; }
5597 s_len = std::strlen(s);
5599 f_len = t_len + std::strlen(f);
5602 if(rv) { d_len = 0; }
else { d_len = t_len + (std::size_t) 20; }
5606 l_len = t_len + (std::size_t) 11;
5607 #else // USE_LINE_COUNT
5609 #endif // USE_LINE_COUNT
5610 #if USE_ARTICLE_NUMBER
5622 else { a_len += t_len; }
5623 #else // USE_ARTICLE_NUMBER
5625 #endif // USE_ARTICLE_NUMBER
5627 ss =
new char[s_len + f_len + d_len + l_len + a_len + (std::size_t) 1];
5631 ii = 0;
while(s[ii])
5638 if (0x09 == (
int) s_tmp) { ss[ssi++] =
' '; }
5639 else { ss[ssi++] = s_tmp; }
5643 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5646 f_tmp =
new char[f_len + (std::size_t) 1];
5647 std::strcpy(f_tmp, f);
5648 stripAngleAddress(f_tmp);
5649 ii = 0;
while(f_tmp[ii]) { ss[ssi++] = f_tmp[ii++]; }
5655 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5656 ii = 0;
while(d[ii]) { ss[ssi++] = d[ii++]; }
5661 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5662 ii = 0;
while(l[ii]) { ss[ssi++] = l[ii++]; }
5663 #endif // USE_LINE_COUNT
5666 #if USE_ARTICLE_NUMBER
5667 ii = 0;
while(t[ii]) { ss[ssi++] = t[ii++]; }
5668 ii = 0;
while(a[ii]) { ss[ssi++] = a[ii++]; }
5669 #endif // USE_ARTICLE_NUMBER
5679 if(child_of_root_node)
5683 for(iii = 0; iii < cti->children(); ++iii)
5692 if(NULL != h2->
refs)
5694 if(!strcmp(h2->
refs[0], h->
refs[0]))
5696 rti = cti->child(iii);
5702 if(NULL == rti) { rti = cti; }
5703 nti = articleTree->add(rti, ss);
5705 else { nti = articleTree->add(cti, ss); }
5712 for(rti = articleTree->next(articleTree->first());
5713 rti; rti = articleTree->next(rti))
5723 if(rn >= n) { match =
true; }
5728 if(rn < n) { match =
true; }
5738 if(rd >= d_raw) { match =
true; }
5743 if(rd < d_raw) { match =
true; }
5748 nti = articleTree->insert_above(rti, ss);
5752 if(NULL == rti) { nti = articleTree->add(articleTree->root(), ss); }
5755 nti->user_data((
void*) che->
child[i]);
5764 if(0 < score) { nti->usericon(&pm_score_up); }
5768 nti->usericon(&pm_reply_to_own);
5773 nti->usericon(&pm_score_down);
5784 nti->labelfont(FL_HELVETICA);
5788 if(kill_threshold > score)
5792 printf(
"%s: %sKill article with score %d (threshold: %d)\n",
5795 articleTree->remove(nti);
5804 if(NULL != tmp) { res = tmp; }
5807 if(group_list[group_list_index].last_viewed == che->
child[i]->
anum)
5816 groupListUpdateEntry(group_list_index);
5825 void MainWindow::updateTree(
void)
5830 Fl_Tree_Item* child_of_root;
5831 Fl_Tree_Item* sti = NULL;
5833 bool unread_articles_present;
5836 bool recalculate =
true;
5839 articleTree->update_in_progress(
true);
5842 articleTree->redraw();
5843 articleTree->not_drawn();
5845 while(!articleTree->drawn()) { Fl::wait(0.10); }
5848 rti = articleTree->root();
5851 articleTree->add(
"X");
5852 rti = articleTree->root();
5855 articleTree->clear_children(rti);
5858 articleTree->redraw();
5859 articleTree->not_drawn();
5861 while(!articleTree->drawn()) { Fl::wait(0.10); }
5865 if(!rv) { sti = addTreeNodes(rti, che); }
5874 recalculate =
false;
5875 rv = rti->children();
5876 for(i = 0; i < rv; ++i)
5878 if(FL_HELVETICA_BOLD == rti->child(i)->labelfont())
5880 unread_articles_present =
true;
5884 unread_articles_present
5885 = checkTreeBranchForUnread(rti->child(i));
5887 if(!unread_articles_present)
5890 if( rti->child(i) == sti
5891 || checkTreeBranchForItem(rti->child(i), sti) )
5896 articleTree->remove(rti->child(i));
5903 if(!rti->children())
5905 ti = articleTree->add(S(
"No articles"));
5909 ti->labelfont(FL_HELVETICA);
5910 ti->user_data(NULL);
5917 rv = rti->children();
5918 for(i = 0; i < rv; ++i)
5920 unread_articles_present = checkTreeBranchForUnread(rti->child(i));
5921 if(unread_articles_present)
5923 rti->child(i)->labelfont(FL_HELVETICA_BOLD);
5933 while(NULL != (ti = articleTree->next(ti)))
5939 while(articleTree->root() != oi)
5941 if(!articleTree->open(oi)) { articleTree->open(oi, 1); }
5942 for(i = 0; i < articleTree->root()->children(); ++i)
5944 if(articleTree->root()->child(i) == oi)
5950 if(abort) {
break; }
5951 oi = articleTree->prev(oi);
5954 articleTree->set_item_focus(ti);
5955 articleTree->select(ti, 1);
5956 Fl::focus(articleTree);
5969 child_of_root = rti->child(rti->children() - 1);
5974 child_of_root = rti->child(0);
5976 scrollTree(UI_SCROLL_BOTTOM, child_of_root);
5977 articleTree->set_item_focus(child_of_root);
5978 Fl::focus(articleTree);
5981 currentArticle->text(
"");
5982 currentStyle->text(
"");
5984 articleTree->redraw();
5986 articleTree->update_in_progress(
false);
5994 void MainWindow::updateArticleTree(
int action)
5999 if(UI_CB_START == action)
6001 if(!stateMachine(EVENT_AT_REFRESH)) { rv = 1; }
6006 #ifdef FL_ABI_VERSION
6007 # if 10303 <= FL_ABI_VERSION
6009 articleTree->hposition(0);
6010 # endif // 10303 <= FL_ABI_VERSION
6011 #endif // FL_ABI_VERSION
6017 if(!currentGroup->eac) { rv = 2; }
6021 ai = currentGroup->lwm;
6022 UI_STATUS(S(
"Update article tree ..."));
6025 ai_range.
first = currentGroup->lwm;
6026 ai_range.
last = currentGroup->hwm;
6027 ai_range.
next = NULL;
6050 if(0 >= rv || 2 == rv)
6071 if(UI_CB_FINISH == action)
6082 (std::size_t) currentGroup->hwm - currentGroup->lwm);
6084 if(currentGroup->hwm == ai++)
6093 if(0 > rv) { state = -1; }
6108 PRINT_ERROR(
"Adding article to hierarchy failed");
6119 groupList->deselect();
6120 groupList->select(groupSelect_cb_state);
6122 if(!stateMachine(EVENT_AT_REFRESH_EXIT))
6124 PRINT_ERROR(
"Error in main window state machine");
6146 UI_STATUS(S(
"Updating article tree failed."));
6151 PRINT_ERROR(
"Invalid state while updating article tree");
6153 UI_STATUS(S(
"Updating article tree failed."));
6165 void MainWindow::articleUpdate(Fl_Text_Buffer* article)
6167 static bool init =
true;
6169 const char* url[] = {
"http://",
"https://",
"ftp://",
"nntp://",
6170 "file://",
"news:",
"mailto:", NULL };
6171 const std::size_t url_len[] = { 7, 8, 6, 7, 7, 5, 7 };
6172 const char bold =
'A';
6173 const char sig =
'B';
6174 const char cit =
'C';
6175 const char link =
'D';
6176 const char plain =
'E';
6177 const char l1 =
'F';
6178 const char l2 =
'G';
6179 const char l3 =
'H';
6180 const char l4 =
'I';
6181 Fl_Text_Buffer* ca = currentArticle;
6186 std::size_t iii = 0;
6191 bool references =
false;
6195 bool signature =
false;
6196 bool citation =
false;
6197 bool hyperlink =
false;
6199 bool cl_lock =
false;
6204 hyperlinkStyle = (
unsigned int) (
unsigned char) link;
6209 PRINT_ERROR(
"Article update request without content ignored (bug)");
6212 gui_check_article(article);
6213 currentArticle = article;
6214 text->buffer(currentArticle);
6216 if(ca) {
delete ca; }
6219 gui_process_shy(currentArticle);
6222 if(currentStyle) {
delete currentStyle; }
6223 style = currentArticle->text();
6224 if(NULL == style) { len = 0; }
6225 else { len = std::strlen(style); }
6226 if(INT_MAX < len) { len = INT_MAX; }
6227 for(i = 0; i < len; ++i)
6229 if(
'\n' == style[i])
6245 if(
' ' == c || 0x09 == (
int) c ||
'>' == c ||
'"' == c)
6251 if(sol && (
'|' == style[i] ||
'!' == style[i]))
6253 if(!hyperlink) { citation =
true; }
6256 if(sol) { sol =
false; delim =
true; ss = 0; cl = 0; ii = 0; }
6265 for(iiii = i - ii; iiii < i; ++iiii)
6267 if(
'_' != currentArticle->byte_at((
int) iiii)) {
break; }
6271 for(iiii = 0; iiii <= ii; ++iiii)
6273 style[i - iiii] = plain;
6285 if(
'_' != style[i]) { hs = bold; }
else { hs = plain; }
6288 if(
'|' == style[i] && 79U <= iii) { ready =
true; }
6289 else if(
'_' == style[i]) { ++iii; }
6290 if(
':' == style[i]) { hs = plain; }
6292 if(0x1D == (
int) style[i]) { references =
true; }
6296 if(0x30 <= style[i] && 0x39 >= style[i]) { hs = link; }
6297 else { hs = plain; }
6304 if(
'-' == style[i] && !ii) { ss = 1; }
6305 if(
'-' == style[i] && 1U == ii && 1 == ss) { ss = 2; }
6306 if(
' ' == style[i] && 2U == ii && 2 == ss)
6309 if((
char) 0x0A == style[i + 1U])
6311 if(gui_last_sig_separator(&style[i + 1U]))
6313 style[i] = sig; style[i - 1U] = sig; style[i - 2U] = sig;
6320 while(NULL != url[url_i])
6322 if(!std::strncmp(&style[i], url[url_i], url_len[url_i]))
6333 if(
' ' == c || 0x09 == (
int) c ||
'<' == c ||
'"' == c)
6337 else { delim =
false; }
6343 if(
'>' == style[i]) { cl_lock =
false; }
6344 else { cl_lock =
true; }
6346 if(
'>' == style[i] && !cl_lock) { ++cl; }
6347 if(
'>' != style[i] &&
' ' != style[i] && (
char) 9 != style[i])
6351 if(4U < cl) { cl = 1; }
6354 case 1: { style[i] = l1;
break; }
6355 case 2: { style[i] = l2;
break; }
6356 case 3: { style[i] = l3;
break; }
6357 case 4: { style[i] = l4;
break; }
6358 default: { style[i] = plain;
break; }
6363 if(signature) { style[i] = sig; }
6364 if(citation && !signature) { style[i] = cit; }
6365 if(hyperlink) { style[i] = link; }
6368 currentStyle =
new Fl_Text_Buffer((
int) len, 0);
6369 if(NULL != style) { currentStyle->text(style); }
6370 std::free((
void*) style);
6373 if(init) { init =
false; }
6377 text->highlight_data(currentStyle, styles, styles_len,
'A', NULL, NULL);
6381 if (1 == currentArticle->findchar_forward(0, 0x1DU, &pos))
6383 currentArticle->replace(pos, pos + 1,
" ");
6396 return(gui_print_header_fields(h));
6404 void MainWindow::articleSelect(
int action)
6409 const char* p = NULL;
6410 const char* q = NULL;
6413 bool overview =
false;
6414 bool process =
false;
6417 if(NULL == currentArticleHE)
6420 SC(
"Do not use non-ASCII for the translation of this item")
6421 fl_message_title(S("Error"));
6422 fl_alert("%s", "Fatal error detected in 'articleSelect()' (bug)");
6430 if(UI_CB_START == action)
6433 if(!stateMachine(EVENT_A_SELECT)) { rv = 1; }
6434 else if(currentArticleHE)
6477 wrapMode = Fl_Text_Display::WRAP_NONE;
6478 text->wrap_mode(wrapMode, 0);
6480 if(!overview) { q = p; }
6485 eoh = std::strstr(raw,
"\r\n\r\n");
6498 currentArticleHE->anum, p);
6499 if(0 > rv) { process =
false; }
6506 UI_STATUS(S(
"Download of article failed."));
6509 currentArticle->text(
"");
6510 currentStyle->text(
"");
6515 UI_STATUS(S(
"Article successfully downloaded."));
6517 tb =
new Fl_Text_Buffer(0, 0);
6521 std::printf(
"\nArticle watermark ............: %lu\n",
6522 currentArticleHE->anum);
6523 std::printf(
"MIME version .................: %s\n",
6524 currentArticleHE->header->mime_v);
6525 std::printf(
"MIME content transfer encoding: %s\n",
6526 currentArticleHE->header->mime_cte);
6527 std::printf(
"MIME content type ............: %s\n",
6528 currentArticleHE->header->mime_ct);
6531 hdr = printHeaderFields(currentArticleHE->header);
6540 if(NULL != mimeData) {
delete mimeData; }
6541 mimeData =
new MIMEContent(currentArticleHE->header, q);
6543 gui_decode_mime_entities(tb, mimeData,
6544 currentArticleHE->header->msgid);
6548 group_list[group_list_index].last_viewed = currentArticleHE->anum;
6552 currentArticleHE->anum);
6553 groupListUpdateEntry(group_list_index);
6555 if(!process) { currentArticleHE = NULL; }
6559 currentSearchPosition = 0;
6561 if(!stateMachine(EVENT_A_SELECT_EXIT))
6563 PRINT_ERROR(
"Error in main window state machine");
6573 void MainWindow::viewMotd(
int action)
6576 std::ostringstream titleString;
6577 const char* motd = NULL;
6580 if(UI_CB_START == action)
6582 if(!stateMachine(EVENT_MOTD_VIEW)) { rv = 1; }
6586 UI_STATUS(S(
"Get message of the day ..."));
6603 if(0 > rv) {
UI_STATUS(S(
"No message of the day or download failed.")); }
6610 UI_STATUS(S(
"Message of the day successfully downloaded."));
6622 SC("Do not use characters for the translation that cannot be")
6623 SC("converted to the ISO 8859-1 character set for this item.")
6624 SC("Leave the original
string in place if in doubt.")
6625 titleString << S("Message of the day") << std::flush;
6638 const std::
string& ts = titleString.str();
6641 #if CFG_USE_XSI && !CFG_NLS_DISABLE
6647 title = gui_utf8_iso(ts.c_str());
6651 new MotdWindow(motd, title);
6655 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
6657 new MotdWindow(motd, ts.c_str());
6658 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
6663 if(!stateMachine(EVENT_MOTD_VIEW_EXIT))
6665 PRINT_ERROR(
"Error in main window state machine");
6677 void MainWindow::viewArticle(
int action,
const char* mid)
6679 static const char debug_prefix[] =
"Try to fetch article: ";
6681 std::ostringstream titleString;
6682 const char* article;
6686 if(UI_CB_START == action)
6688 if(!stateMachine(EVENT_A_VIEW)) { rv = 1; }
6689 else if(NULL != mid)
6695 mid_a =
new char[std::strlen(mid) + (std::size_t) 3];
6697 std::strcpy(&mid_a[1], mid);
6698 std::strcat(mid_a,
">");
6702 len += std::strlen(debug_prefix);
6703 len += std::strlen(mid_a);
6704 sbuf =
new char[len + (std::size_t) 1];
6706 std::strcat(sbuf, debug_prefix);
6707 std::strcat(sbuf, mid_a);
6730 UI_STATUS(S(
"Downloading article failed."));
6731 SC(
"Do not use non-ASCII for the translation of this item")
6732 fl_message_title(S("Error"));
6733 fl_alert("%s", S("Article not found"));
6741 UI_STATUS(S(
"Article successfully downloaded."));
6745 SC("Do not use characters for the translation that cannot be")
6746 SC("converted to the ISO 8859-1 character set for this item.")
6747 SC("Leave the original
string in place if in doubt.")
6748 titleString << S("Article") << std::flush;
6761 const std::
string& ts = titleString.str();
6764 #if CFG_USE_XSI && !CFG_NLS_DISABLE
6770 title = gui_utf8_iso(ts.c_str());
6774 new ArticleWindow(article, title);
6778 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
6780 new ArticleWindow(article, ts.c_str());
6781 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
6785 if(!stateMachine(EVENT_A_VIEW_EXIT))
6787 PRINT_ERROR(
"Error in main window state machine");
6797 void MainWindow::viewSrc(
int action)
6800 std::ostringstream titleString;
6801 const char* article;
6803 if(UI_CB_START == action)
6805 if(!stateMachine(EVENT_SRC_VIEW)) { rv = 1; }
6806 else if(NULL != currentArticleHE)
6809 UI_STATUS(S(
"Get article source code ..."));
6826 if(0 > rv) {
UI_STATUS(S(
"Downloading article source code failed.")); }
6833 UI_STATUS(S(
"Article source code successfully downloaded."));
6837 SC("Do not use characters for the translation that cannot be")
6838 SC("converted to the ISO 8859-1 character set for this item.")
6839 SC("Leave the original
string in place if in doubt.")
6840 titleString << S("Article source code") << std::flush;
6853 const std::
string& ts = titleString.str();
6856 #if CFG_USE_XSI && !CFG_NLS_DISABLE
6862 title = gui_utf8_iso(ts.c_str());
6866 new ArticleSrcWindow(article, title);
6870 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
6872 new ArticleSrcWindow(article, ts.c_str());
6873 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
6877 if(!stateMachine(EVENT_SRC_VIEW_EXIT))
6879 PRINT_ERROR(
"Error in main window state machine");
6896 void MainWindow::articleCompose(
bool reply,
bool super)
6899 std::ostringstream titleString;
6902 const char* cq = NULL;
6909 Fl_Text_Buffer header;
6910 const char*
msgid = NULL;
6911 const char* ckey1 = NULL;
6912 const char* ckey = NULL;
6914 const char* datetime;
6915 bool headerOK =
true;
6919 unsigned int c = (
unsigned int)
'\n';
6921 const char* field_name;
6924 bool insertedMessageID =
false;
6930 if(!stateMachine(EVENT_COMPOSE)) {
return; }
6932 if(NULL == currentGroup)
6934 SC(
"Do not use non-ASCII for the translation of this item")
6935 fl_message_title(S("Error"));
6936 fl_alert("%s", S("No group selected"));
6938 else if((reply || super) && NULL == currentArticleHE)
6940 SC(
"Do not use non-ASCII for the translation of this item")
6941 fl_message_title(S("Error"));
6942 fl_alert("%s", S("No article selected"));
6946 if(reply || super) { hdr = currentArticleHE->header; }
6952 if(reply && !super && NULL != hdr->
fup2)
6954 if(!std::strcmp(
"poster", hdr->
fup2))
6956 SC(
"Do not use non-ASCII for the translation of this item")
6957 fl_message_title(S("Warning"));
6958 rv = fl_choice("%s", S("Cancel"),
6961 S("Really execute Followup-To to poster?"));
6962 if(1 == rv) { sendEmail(); }
6963 if(!rv || 1 == rv) { abort =
true; }
6972 if(currentArticle->selected())
6975 p = currentArticle->selection_text();
6976 if(NULL != p) { cq = p; }
6981 p = currentArticle->text();
6985 while(
'_' != p[i++]);
6986 while(
'|' != p[i++]);
6987 while(
'|' != p[i++]);
6994 sig_delim = std::strstr(q,
"\n-- \n");
6995 if(NULL == sig_delim) {
break; }
6996 else { sig = q = &sig_delim[1]; }
6998 if(NULL != sig) { sig[0] = 0; }
7002 len = std::strlen(hdr->
from);
7003 from =
new char[++len];
7005 stripAngleAddress(
from);
7012 cq =
"Reason for cancel unknown.\n";
7032 header.append(
"Path: not-for-mail\n");
7033 if(std::strlen(fqdn))
7035 header.append(
"Message-ID: ");
7037 if(NULL ==
msgid) { headerOK =
false; }
7040 header.append(
msgid);
7041 insertedMessageID =
true;
7044 header.append(
"\n");
7048 SC(
"Do not use non-ASCII for the translation of this item")
7049 fl_message_title(S("Error"));
7050 fl_alert("%s", S("From: header field not configured"));
7055 field_name =
"From: ";
7057 std::strlen(field_name));
7058 if(NULL == field) { headerOK =
false; }
7061 header.append(field_name);
7062 header.append(field);
7063 header.append(
"\n");
7068 std::strlen(field_name));
7069 if(NULL == field2) { headerOK =
false; }
7072 if(std::strcmp(field, field2))
7074 SC(
"Do not use non-ASCII for the translation of this item")
7075 fl_message_title(S("Error"));
7076 fl_alert("%s", S("Supersede or cancel not allowed"));
7085 header.append("Newsgroups: ");
7086 if(!super && !reply) { header.append(currentGroup->name); }
7092 if(!super && NULL != hdr->
fup2)
7094 if(std::strcmp(
"poster", hdr->
fup2))
7096 SC(
"Do not use non-ASCII for the translation of this item")
7097 fl_message_title(S("Note"));
7098 fl_message("%s", S("Followup-To specified
groups executed"));
7099 header.append(hdr->
fup2);
7100 len += std::strlen(hdr->
fup2);
7110 if(i) { header.append(
","); }
7112 header.append(hdr->
groups[i]);
7113 len += std::strlen(hdr->
groups[i]);
7115 while(NULL != hdr->
groups[++i]);
7118 if((std::size_t) 998 < len) { headerOK =
false; }
7120 header.append(
"\n");
7121 header.append(
"Subject: ");
7127 header.append(
"Re: ");
7137 if(NULL == hdr->
msgid) { headerOK =
false; }
7140 header.append(
"cmsg cancel ");
7141 header.append(hdr->
msgid);
7144 header.append(
"\n");
7148 rv = header.search_forward(0,
"Subject:", &start, 1);
7152 if(0 < start) { c = header.char_at(start - 1); }
7153 if((
unsigned int)
'\n' == c)
7156 rv = header.findchar_forward(start, (
unsigned int)
'\n', &end);
7159 rv = header.search_forward(start,
"(was:", &pos, 0);
7162 header.remove(pos, end);
7165 if((
unsigned int)
' ' == header.char_at(pos - 1))
7167 header.remove(pos - 1, pos);
7175 header.append(
"Date: ");
7177 if(NULL == datetime) { headerOK =
false; }
7178 else { header.append(datetime); }
7179 header.append(
"\n");
7181 if(insertedMessageID)
7186 if(NULL != ckey1 || NULL != ckey)
7188 header.append(
"Cancel-Lock: ");
7189 if(NULL != ckey1) { header.append(ckey1); }
7190 if(NULL != ckey1 && NULL != ckey) { header.append(
" " ); }
7191 if(NULL != ckey) { header.append(ckey); }
7192 header.append(
"\n");
7201 header.append(
"Injection-Date: ");
7202 header.append(datetime);
7203 header.append(
"\n");
7210 if(NULL ==
msgid) { headerOK =
false; }
7215 header.append(
"Supersedes: ");
7216 header.append(
msgid);
7217 header.append(
"\n");
7221 header.append(
"Control: cancel ");
7222 header.append(
msgid);
7223 header.append(
"\n");
7225 if(insertedMessageID)
7230 if(NULL != ckey1 || NULL != ckey)
7232 header.append(
"Cancel-Key: ");
7233 if(NULL != ckey1) { header.append(ckey1); }
7234 if(NULL != ckey1 && NULL != ckey) { header.append(
" " ); }
7235 if(NULL != ckey) { header.append(ckey); }
7236 header.append(
"\n");
7245 field_name =
"Reply-To: ";
7247 std::strlen(field_name));
7248 if(NULL == field) { headerOK =
false; }
7251 header.append(field_name);
7252 header.append(field);
7253 header.append(
"\n");
7266 if(!(NULL == hdr->
refs && super))
7268 header.append(
"References: ");
7269 inspos = header.length();
7271 header.append(
"\n");
7275 header.insert(inspos, hdr->
msgid);
7276 len += std::strlen(hdr->
msgid);
7278 if(NULL != hdr->
refs)
7280 if(NULL != hdr->
refs[0])
7284 len += std::strlen(hdr->
refs[0]);
7287 while(NULL != hdr->
refs[i]) { ++i; }
7290 len += std::strlen(hdr->
refs[i]);
7294 header.insert(inspos,
" ");
7295 header.insert(inspos, hdr->
refs[i]);
7299 header.insert(inspos,
" ");
7300 header.insert(inspos, hdr->
refs[0]);
7306 header.append(
"Organization: ");
7308 header.append(
"\n");
7312 header.append(
"User-Agent: " CFG_NAME
"/" CFG_VERSION
7313 " (for " CFG_OS
")\n");
7318 header.append(
"MIME-Version: 1.0\n");
7320 header.append(
"\n");
7323 if(
true != headerOK)
7325 SC(
"Do not use non-ASCII for the translation of this item")
7326 fl_message_title(S("Error"));
7327 fl_alert("%s", S("Creating message header failed"));
7331 const char* header_text;
7332 header_text = header.text();
7333 if(NULL != header_text)
7337 SC("Do not use characters for the translation that cannot be")
7338 SC("converted to the ISO 8859-1 character set for the items")
7339 SC("in this section.")
7340 SC("Leave the original strings in place if in doubt.")
7343 titleString << S(
"Compose followup or reply") << std::flush;
7345 else { titleString << S(
"Compose new article") << std::flush; }
7357 const std::
string& ts = titleString.str();
7360 #if CFG_USE_XSI && !CFG_NLS_DISABLE
7366 title = gui_utf8_iso(ts.c_str());
7370 composeWindow =
new ComposeWindow(title, header_text, cq,
from,
7376 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
7378 composeWindow =
new ComposeWindow(ts.c_str(), header_text, cq,
from,
7381 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
7383 std::free((
void*) header_text);
7388 if(NULL !=
from) {
delete[]
from; }
7389 std::free((
void*) p);
7394 if(!stateMachine(EVENT_COMPOSE_EXIT))
7396 PRINT_ERROR(
"Error in main window state machine");
7409 void MainWindow::articlePost(
int action,
const char* article)
7421 free_method = FM_DEFAULT;
7422 if(UI_CB_START == action)
7424 if(!stateMachine(EVENT_POST)) { rv = 1; }
7434 SC(
"Do not use non-ASCII for the translation of this item")
7435 fl_message_title(S("Error"));
7436 fl_alert("%s", S("Conversion
from local to canonical form failed"));
7443 std::free((
void*) article);
7445 free_method = FM_CORE;
7452 SC(
"Do not use non-ASCII for the translation of this item")
7453 fl_message_title(S("Error"));
7454 fl_alert("%s", S("External postprocessor failed"));
7461 if(FM_CORE == free_method) {
core_free((
void*) article); }
7462 else { std::free((
void*) article); }
7464 free_method = FM_EXT;
7486 std::free((
void*) article);
7503 if(!stateMachine(EVENT_POST_EXIT))
7505 PRINT_ERROR(
"Error in main window state machine");
7509 UI_STATUS(S(
"Posting article failed."));
7510 SC(
"Do not use non-ASCII for the translation of this item")
7511 fl_message_title(S("Error"));
7512 fl_alert("%s", S("Posting article failed."));
7517 UI_STATUS(S(
"Article successfully posted."));
7518 if(NULL != composeWindow)
7520 delete composeWindow;
7521 composeWindow = NULL;
7537 Fl_Tree_Item* MainWindow::searchSelectArticle(
const char* target_mid,
7546 ti = articleTree->root();
7548 while(NULL != (ti = articleTree->next(ti)))
7551 if(std::strlen(mid) != tlen + (std::size_t) 2)
7556 if(!std::strncmp(&mid[1], target_mid, tlen))
7560 while(articleTree->root() != oi)
7562 if(!articleTree->open(oi))
7564 articleTree->open(oi, 1);
7566 for(i = 0; i < articleTree->root()->children(); ++i)
7568 if(articleTree->root()->child(i) == oi)
7574 if(abort) {
break; }
7575 oi = articleTree->prev(oi);
7578 articleTree->set_item_focus(ti);
7579 articleTree->deselect_all();
7580 articleTree->select(ti, 1);
7581 Fl::focus(articleTree);
7593 void MainWindow::storeMIMEEntityToFile(
const char* uri,
const char*
msgid)
7595 const char* link = NULL;
7596 const char* start = NULL;
7597 std::size_t len = 0;
7602 const char* suggest = NULL;
7605 link = gui_create_link_to_entity(
msgid, 0);
7606 if(NULL != link && link[0])
7610 p = std::strrchr(start, (
int)
'/');
7613 len = (size_t) (p - start);
7621 fprintf(stderr,
"%s: %sCannot check link to MIME entity (bug)\n",
7626 fprintf(stderr,
"%s: %sClick on link to MIME entity detected:\n",
7630 for(i = 0; len > (std::size_t) i; ++i)
7632 fprintf(stderr,
"%c", start[i]);
7634 fprintf(stderr,
" (Compare, Length: %u)\n", (
unsigned int) len);
7638 if(error || std::strncmp(uri, start, len))
7641 SC(
"Do not use non-ASCII for the translation of this item")
7642 fl_message_title(S("Error"));
7643 fl_alert("%s", S("Link target not found or not supported"));
7648 p = std::strrchr(uri, (
int)
'/');
7649 if(NULL == p || 1 != std::sscanf(++p,
"%u", &i))
7651 PRINT_ERROR(
"Extracting MIME entity number from file URI failed");
7656 const char* entity_body = mimeData->part(i, &cte, NULL);
7657 if(NULL != entity_body)
7659 SC(
"Do not use characters for the translation that cannot be")
7660 SC("converted to the ISO 8859-1 character set for this item.")
7661 SC("Leave the original
string in place if in doubt.")
7662 const
char* title = S("Save attachment");
7666 if(NULL != mimeData->filename(i))
7669 name = (
char*) std::malloc(std::strlen(homedir)
7670 + std::strlen(mimeData->filename(i))
7675 std::strcpy(name, homedir);
7676 std::strcat(name,
"/");
7677 std::strcat(name, mimeData->filename(i));
7685 if (NULL != suggest)
7687 fl_file_chooser_ok_label(S(
"Save"));
7688 const char* pathname =
7689 fl_file_chooser(title,
"*", suggest, 0);
7690 if(NULL != pathname)
7697 SC(
"Do not use non-ASCII for the translation of this item")
7698 fl_message_title(S("Error"));
7700 S("Pathname conversion to locale codeset failed"));
7708 SC(
"Do not use non-ASCII for the translation of this item")
7709 fl_message_title(S("Error"));
7710 fl_alert("%s", S("Operation failed"));
7721 std::free((
void*) link);
7722 std::free((
void*) suggest);
7729 void MainWindow::hyperlinkHandler(
int pos)
7731 const char* mailto =
"mailto:";
7732 const char* news =
"news:";
7733 const char* nntp =
"nntp:";
7734 const char* file =
"file:";
7751 if(currentArticle && currentStyle)
7756 i = currentArticle->prev_char(i);
7757 if(currentStyle->char_at(i) == hyperlinkStyle) { start = i; }
7763 i = currentArticle->next_char(i);
7764 if(currentStyle->char_at(i) == hyperlinkStyle) { end = i; }
7765 else { ++end;
break; }
7767 uri = currentArticle->text_range(start, end);
7771 len = std::strlen(nntp);
7772 if(std::strlen(uri) >= len && !std::strncmp(uri, nntp, len))
7775 PRINT_ERROR(
"Multi server support missing for nntp URI type");
7776 SC(
"Do not use non-ASCII for the translation of this item")
7777 fl_message_title(S("Error"));
7778 fl_alert("%s", S("URI type is not supported"));
7787 len = std::strlen(news);
7788 if(std::strlen(uri) >= len && !std::strncmp(uri, news, len))
7791 if(!std::strncmp(&uri[len],
"///", 3))
7793 std::memmove(&uri[len], &uri[len + (
size_t) 3],
7794 std::strlen(&uri[len + (
size_t) 3])
7797 if(std::strlen(uri) == len)
7799 SC(
"Do not use non-ASCII for the translation of this item")
7800 fl_message_title(S("Error"));
7801 fl_alert("%s", S("Invalid URI format"));
7804 else if(std::strchr(&uri[len], (
int) '/'))
7806 SC(
"Do not use non-ASCII for the translation of this item")
7807 fl_message_title(S("Error"));
7809 S("Server specification in URI not supported"));
7813 else if(!std::strchr(&uri[len], (
int) '@'))
7816 if(std::strchr(&uri[len], (
int)
'*')
7817 || std::strchr(&uri[len], (
int)
'?'))
7819 SC(
"Do not use non-ASCII for the translation of this item")
7820 fl_message_title(S("Error"));
7821 fl_alert("%s", S("URI doesn't specify a single group"));
7828 SC(
"Do not use non-ASCII for the translation of this item")
7829 fl_message_title(S("Error"));
7830 fl_alert("%s", S("Invalid URI format"));
7837 for(gi = 0; gi < group_num; ++gi)
7839 clen = std::strlen(&uri[len]);
7840 if(std::strlen(group_list[gi].name) == clen)
7842 if(!strncmp(&uri[len], group_list[gi].name,
7845 if((std::size_t) INT_MAX >= ++gi)
7847 groupList->deselect();
7848 groupList->select((
int) gi);
7849 groupSelect(UI_CB_START, (
int) gi);
7860 fl_message_title(S(
"Note"));
7861 rv = fl_choice(
"%s", S(
"No"),
7864 S(
"URI specifies a group that is not subscribed.\nSubscribe now?"));
7867 rv = groupStateMerge();
7873 UI_STATUS(S(
"Group subscription stored."));
7876 if(NULL != mainWindow)
7879 mainWindow->groupListImport();
7885 S(
"Click URI again after operation is complete"));
7898 SC(
"Do not use non-ASCII for the translation of this item")
7899 fl_message_title(S("Error"));
7900 fl_alert("%s", S("Invalid URI format"));
7904 clen = std::strlen(&uri[len]);
7905 ti = searchSelectArticle(&uri[len], clen);
7911 printf(
"%s: %sTry to fetch article from URI\n",
7914 viewArticle(UI_CB_START, (
const char*) &uri[len]);
7922 clen = std::strlen(uri);
7923 if(std::strspn(uri,
"0123456789") == clen)
7926 if((std::size_t) INT_MAX >= clen && (std::size_t) 20 >= clen)
7931 p = currentArticleHE->header->refs[ref_i];
7932 clen = std::strlen(p);
7934 std::strncpy(q, &p[1], clen - (std::size_t) 2);
7935 q[clen - (std::size_t) 2] = 0;
7936 viewArticle(UI_CB_START, q);
7944 len = std::strlen(mailto);
7945 if(std::strlen(uri) >= len && !std::strncmp(uri, mailto, len))
7947 if(std::strlen(uri) == len)
7949 SC(
"Do not use non-ASCII for the translation of this item")
7950 fl_message_title(S("Error"));
7951 fl_alert("%s", S("Invalid URI format"));
7966 len = std::strlen(file);
7967 if(std::strlen(uri) >= len
7968 && !std::strncmp(uri, file, len))
7970 if(std::strlen(uri) == len)
7972 SC(
"Do not use non-ASCII for the translation of this item")
7973 fl_message_title(S("Error"));
7974 fl_alert("%s", S("Invalid URI format"));
7979 storeMIMEEntityToFile(uri,
7980 currentArticleHE->header->msgid);
7988 if(0 > rv && invalid)
7990 SC(
"Do not use non-ASCII for the translation of this item")
7991 fl_message_title(S("Error"));
7992 fl_alert("%s", S("Invalid characters in URI"));
7996 SC(
"Do not use non-ASCII for the translation of this item")
7997 fl_message_title(S("Error"));
7998 fl_alert("%s", S("Starting external URI handler failed"));
8007 std::free((
void*) uri);
8020 MainWindow::MainWindow(const
char* label) :
8021 UI_WINDOW_CLASS(730, 395, label)
8023 const char* enabled = S(
"Enabled");
8024 const char* disabled = S(
"Disabled");
8025 const char* available = S(
"Available");
8026 const char* notavailable = S(
"Not available");
8036 FL_FOREGROUND_COLOR,
8042 FL_FOREGROUND_COLOR,
8048 Fl_Group* mainGroup;
8049 Fl_Group* statusGroup;
8054 mainState = STATE_READY;
8058 wrapMode = Fl_Text_Display::WRAP_NONE;
8060 hyperlinkPosition = -1;
8066 group_list_index = 0;
8069 subscribedGroups = NULL;
8070 currentGroup = NULL;
8071 currentArticle = NULL;
8072 currentStyle = NULL;
8073 lastArticleHE = NULL;
8074 currentArticleHE = NULL;
8078 p =
new char[1]; p[0] = 0;
8079 currentSearchString = p;
8080 currentSearchPosition = 0;
8083 progress_skip_update =
false;
8089 subscribeWindow = NULL;
8092 composeWindow = NULL;
8093 composeWindowLock = 0;
8096 callback(exit_cb, (
void*)
this);
8099 aboutString << enabled << disabled << available << notavailable;
8100 aboutString.str(std::string());
8101 aboutString.clear();
8104 aboutString << CFG_NAME <<
" " << CFG_VERSION
8105 <<
" " << S(
"for") <<
" " << CFG_OS <<
"\n"
8106 #if defined(CFG_MODIFIED) && CFG_MODIFIED != 0
8108 <<
"(This is a modified version!)" <<
"\n"
8109 #endif // CFG_MODIFIED
8111 << S(
"Unicode version") <<
": " << UC_VERSION <<
"\n"
8114 #if CFG_USE_XSI && !CFG_NLS_DISABLE
8115 << S(
"Enabled") <<
"\n"
8116 #else // CFG_USE_XSI && !CFG_NLS_DISABLE
8117 << S(
"Disabled") <<
"\n"
8118 #endif // CFG_USE_XSI && !CFG_NLS_DISABLE
8122 << S(
"Available") <<
"\n"
8123 << S(
"Required OpenSSL ABI") <<
": "
8124 # if CFG_USE_LIBRESSL
8125 <<
"LibreSSL" <<
"\n"
8126 # else // CFG_USE_LIBRESSL
8127 # if !CFG_USE_OPENSSL_API_3 && !CFG_USE_OPENSSL_API_1_1
8129 # else // !CFG_USE_OPENSSL_API_3 && !CFG_USE_OPENSSL_API_1_1
8130 # if !CFG_USE_OPENSSL_API_3
8132 # else // !CFG_USE_OPENSSL_API_3
8134 # endif // !CFG_USE_OPENSSL_API_3
8135 # endif // !CFG_USE_OPENSSL_API_3 && !CFG_USE_OPENSSL_API_1_1
8136 # endif // CFG_USE_LIBRESSL
8137 #else // CFG_USE_TLS
8138 << S(
"Not available") <<
"\n"
8139 #endif // CFG_USE_TLS
8141 << S(
"Required FLTK ABI") <<
": " << FL_MAJOR_VERSION <<
"."
8143 #ifdef FL_ABI_VERSION
8144 <<
"." << FL_ABI_VERSION % 100
8145 #else // FL_ABI_VERSION
8147 #endif // FL_ABI_VERSION
8150 << S(
"FLTK Double Buffering: ")
8152 << S(
"Disabled") <<
"\n"
8153 #else // CFG_DB_DISABLE
8154 << S(
"Enabled") <<
"\n"
8155 #endif // CFG_DB_DISABLE
8157 << S(
"Compression: ")
8158 #if CFG_CMPR_DISABLE
8159 << S(
"Disabled") <<
"\n"
8160 #else // CFG_CMPR_DISABLE
8164 # endif // CFG_USE_ZLIB
8166 #endif // CFG_CMPR_DISABLE
8168 <<
"Build: " << BDATE << std::flush;
8177 mainGroup =
new Fl_Group(0, 0, 730, 395);
8181 #if CFG_COCOA_SYS_MENUBAR
8182 menu =
new Fl_Sys_Menu_Bar(0, 0, 730, 0);
8183 #else // CFG_COCOA_SYS_MENUBAR
8184 menu =
new Fl_Menu_Bar(0, 0, 730, 30);
8185 #endif // CFG_COCOA_SYS_MENUBAR
8186 menu->selection_color(UI_COLOR_MENU_SELECTION);
8187 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
8189 menu->box(FL_THIN_UP_BOX);
8190 #else // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
8191 menu->box(FL_FLAT_BOX);
8192 #endif // defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
8195 SC("This section is for the
main window menubar and pull-down menus.")
8196 SC("The 2 spaces after every
string are intended and must be preserved.")
8197 SC("The part before the slash is the menubar entry and must be unique.")
8198 SC("The character after & is the key to pull-down a menu with 'Alt-key'.")
8199 SC("You can assign the & to any character before the slash,")
8200 SC("provided again that it is unique in the menubar!")
8201 SC("The part behind the slash is the name of the pull-down menu entry,")
8202 SC("it must only be unique inside the corresponding pull-down menu.")
8203 SC("If the name contains a slash, a submenu is created.")
8205 SC("It is not possible to localize the keyboard shortcuts for the")
8206 SC("pull-down menu entries. It was implemented this way for easier")
8207 SC("documentation and for the possibility to execute blind keyboard")
8208 SC("commands in the case of a misconfigured locale.")
8209 menu->add(S("&File/Save article "), 0, asave_cb, (
void*) this);
8210 menu->add(S("&File/Print article "), 0, print_cb, (
void*) this);
8211 menu->add(S("&File/Quit "), "^q", exit_cb, (
void*) this);
8213 menu->add(S("&Edit/Server "), 0, server_cb, (
void*) this);
8214 menu->add(S("&Edit/Configuration "), 0, config_cb, (
void*) this);
8215 menu->add(S("&Edit/Identity "), 0, identity_cb, (
void*) this);
8219 menu->add(S(
"&Group/Threaded view "),
"^t", thrv_cb, (
void*)
this, i);
8223 menu->add(S(
"&Group/Sort by article number "), 0, uthrv_sort_cb,
8227 menu->add(S(
"&Group/Show only unread articles "), 0, onlyur_cb,
8229 menu->add(S(
"&Group/Subscribe "), 0, gsubscribe_cb, (
void*)
this);
8230 menu->add(S(
"&Group/Unsubscribe "), 0, gunsubscribe_cb, (
void*)
this);
8231 menu->add(S(
"&Group/Sort list "), 0, gsort_cb, (
void*)
this);
8232 menu->add(S(
"&Group/Refresh list "),
"^r", grefresh_cb, (
void*)
this);
8233 menu->add(S(
"&Group/Next unread group "),
"^g", nug_cb, (
void*)
this);
8234 menu->add(S(
"&Group/Mark subthread read "), 0, mssar_cb,
8236 menu->add(S(
"&Group/Mark all in group read "),
"^a", maar_cb,
8238 menu->add(S(
"&Group/Mark all groups read "), 0, magar_cb,
8241 menu->add(S(
"&Article/Search in article "),
"/", asearch_cb, (
void*)
this);
8242 menu->add(S(
"&Article/Post to newsgroup "),
"^p", compose_cb,
8244 menu->add(S(
"&Article/Followup to newsgroup "),
"^f", reply_cb,
8246 menu->add(S(
"&Article/Supersede in newsgroup "), 0, supersede_cb,
8248 menu->add(S(
"&Article/Cancel in newsgroup "), 0, cancel_cb,
8250 menu->add(S(
"&Article/Reply by e-mail "),
"^m", email_cb, (
void*)
this);
8251 menu->add(S(
"&Article/Wrap to width "),
"^w", wrap_cb, (
void*)
this);
8252 menu->add(S(
"&Article/ROT13 "),
"^o", rot13_cb, (
void*)
this);
8253 menu->add(S(
"&Article/Next unread article "),
"^n", nua_cb,
8255 menu->add(S(
"&Article/Previous read article "),
"^b", pra_cb,
8257 menu->add(S(
"&Article/View source "),
"^e", viewsrc_cb, (
void*)
this);
8258 menu->add(S(
"&Article/Toggle read unread "),
"^u", msau_cb,
8263 menu->add(S(
"&Tools/Protocol console "), 0, console_cb, (
void*)
this);
8264 menu->add(S(
"&Tools/Search Message-ID "),
"^s", mid_search_cb,
8267 menu->add(S(
"&Help/About "), 0, about_cb, (
void*)
this);
8268 menu->add(S(
"&Help/Message of the day "), 0, viewmotd_cb, (
void*)
this);
8269 menu->add(S(
"&Help/License "), 0, license_cb, (
void*)
this);
8270 menu->add(S(
"&Help/Bug report "), 0, bug_cb, (
void*)
this);
8275 #if CFG_COCOA_SYS_MENUBAR
8276 contentGroup =
new Fl_Tile(0, 0, 730, 370);
8277 #else // CFG_COCOA_SYS_MENUBAR
8278 contentGroup =
new Fl_Tile(0, 30, 730, 340);
8279 #endif // CFG_COCOA_SYS_MENUBAR
8280 contentGroup->begin();
8283 #if CFG_COCOA_SYS_MENUBAR
8284 groupList =
new My_Multi_Browser(0, 0, 230, 370);
8285 #else // CFG_COCOA_SYS_MENUBAR
8286 groupList =
new My_Multi_Browser(0, 30, 230, 340);
8287 #endif // CFG_COCOA_SYS_MENUBAR
8288 groupList->callback(gselect_cb, (
void*)
this);
8289 #if CFG_COCOA_SYS_MENUBAR
8290 contentGroup2 =
new Fl_Tile(230, 0, 500, 370);
8291 #else // CFG_COCOA_SYS_MENUBAR
8292 contentGroup2 =
new Fl_Tile(230, 30, 500, 340);
8293 #endif // CFG_COCOA_SYS_MENUBAR
8294 contentGroup2->begin();
8297 #if CFG_COCOA_SYS_MENUBAR
8298 articleTree =
new My_Tree(230, 0, 500, 140);
8299 #else // CFG_COCOA_SYS_MENUBAR
8300 articleTree =
new My_Tree(230, 30, 500, 140);
8301 #endif // CFG_COCOA_SYS_MENUBAR
8302 articleTree->showroot(0);
8303 articleTree->connectorstyle(FL_TREE_CONNECTOR_SOLID);
8304 articleTree->connectorcolor(FL_FOREGROUND_COLOR);
8307 articleTree->item_labelfgcolor(FL_FOREGROUND_COLOR);
8308 ti = articleTree->add(S(
"No articles"));
8309 if(NULL != ti) { ti->deactivate(); }
8310 articleTree->callback(aselect_cb, (
void*)
this);
8312 #if CFG_COCOA_SYS_MENUBAR
8313 text =
new My_Text_Display(230, 140, 500, 230);
8314 #else // CFG_COCOA_SYS_MENUBAR
8315 text =
new My_Text_Display(230, 170, 500, 200);
8316 #endif // CFG_COCOA_SYS_MENUBAR
8317 text->callback(hyperlink_cb, (
void*)
this);
8318 text->textfont(FL_COURIER);
8320 contentGroup2->end();
8322 contentGroup->end();
8325 statusGroup =
new Fl_Group(0, 370, 730, 25);
8326 statusGroup->begin();
8329 progressBar =
new Fl_Progress(0, 370, 100, 25);
8331 progressBar->minimum(0.0);
8332 progressBar->maximum(100.0);
8333 progressBar->value(0.0);
8334 progressBar->label(
"");
8336 statusBar =
new Fl_Box(100, 370, 730, 25);
8337 statusBar->box(FL_DOWN_BOX);
8338 statusBar->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
8339 statusBar->label(
"");
8342 statusGroup->resizable(statusBar);
8345 mainGroup->resizable(contentGroup);
8352 styles =
new Fl_Text_Display::Style_Table_Entry[styles_len];
8353 styles[0].color = FL_FOREGROUND_COLOR;
8354 styles[0].font = FL_COURIER_BOLD;
8355 styles[0].size = text->textsize();
8357 for(i = 1; i < styles_len; ++i)
8359 styles[i].color = styles_colors[i];
8360 styles[i].font = text->textfont();
8361 styles[i].size = text->textsize();
8379 MainWindow::~MainWindow(
void)
8381 if(NULL != subscribedGroups)
8385 if(NULL != mimeData) {
delete mimeData; }
8386 delete[] currentSearchString;
8390 text->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
8391 if(currentStyle) {
delete currentStyle; }
8394 text->buffer(dummyTb);
8395 if(currentArticle) {
delete currentArticle; }
8402 int ServerCfgWindow::process(
void)
8405 while(!finished) { Fl::wait(); }
8408 sconf->serverReplace(scfgHostname->value());
8409 sconf->serviceReplace(scfgService->value());
8410 if(scfgTlsStrong->value()) { sconf->enc = UI_ENC_STRONG; }
8411 else if(scfgTlsWeak->value()) { sconf->enc = UI_ENC_WEAK; }
8412 else { sconf->enc = UI_ENC_NONE; }
8413 if(scfgAuthUser->value()) { sconf->auth = UI_AUTH_USER; }
8414 else { sconf->auth = UI_AUTH_NONE; }
8423 ServerCfgWindow::ServerCfgWindow(ServerConfig* sc,
const char* label) :
8424 UI_WINDOW_CLASS(700, 395, label)
8429 int y, w, h, gy, gh, bw;
8431 std::ostringstream serverString;
8432 std::ostringstream serviceString;
8433 std::ostringstream tlsString;
8441 callback(cancel_cb, (
void*)
this);
8444 serverString << S(
"NNTP server hostname")
8445 <<
" (" << S(
"or IP address") <<
")" << std::flush;
8447 serviceString << S(
"Service name")
8448 <<
" (" << S(
"or TCP port") <<
")" << std::flush;
8449 tlsString <<
"Transport Layer Security (TLS)"
8450 <<
" " << S(
"and server to client authentication") << std::flush;
8462 const std::string& srv_s = serverString.str();
8463 const std::string& svc_s = serviceString.str();
8464 const std::string& tls_s = tlsString.str();
8467 hostname =
new char[std::strlen(srv_s.c_str()) + (std::size_t) 1];
8468 std::strcpy(hostname, srv_s.c_str());
8469 service =
new char[std::strlen(svc_s.c_str()) + (std::size_t) 1];
8470 std::strcpy(service, svc_s.c_str());
8471 tls_headline =
new char[std::strlen(tls_s.c_str()) + (std::size_t) 1];
8472 std::strcpy(tls_headline, tls_s.c_str());
8475 scfgGroup =
new Fl_Group(0, 0, 700, 395);
8479 gui_set_default_font();
8480 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
8481 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
8482 if(w1 > w2) { w = w1; }
else { w = w2; }
8483 if(h1 > h2) { h = h1; }
else { h = h2; }
8489 scfgHostname =
new Fl_Input(15, 35, 450, 30, hostname);
8490 scfgHostname->align(FL_ALIGN_TOP_LEFT);
8491 scfgHostname->value(sc->server);
8493 scfgService =
new Fl_Input(480, 35, 205, 30, service);
8494 scfgService->align(FL_ALIGN_TOP_LEFT);
8495 scfgService->value(sc->service);
8497 grpTls =
new Fl_Group(15, 100, 670, 120, tls_headline);
8500 scfgTlsOff =
new Fl_Radio_Round_Button(30, 115, 640, 30,
8503 scfgTlsOff->callback(enc_off_cb, (
void*)
this);
8504 scfgTlsStrong =
new Fl_Radio_Round_Button(30, 145, 640, 30,
8505 S(
"Enabled with strong encryption and forward secrecy"));
8507 scfgTlsStrong->callback(enc_on_cb, (
void*)
this);
8508 scfgTlsWeak =
new Fl_Radio_Round_Button(30, 175, 640, 30,
8509 S(
"Enabled in compatibility mode offering weak cipher suites"));
8511 scfgTlsWeak->callback(enc_on_cb, (
void*)
this);
8514 grpTls->align(FL_ALIGN_TOP_LEFT);
8515 grpTls->box(FL_EMBOSSED_BOX);
8517 grpTls->deactivate();
8518 sc->enc = UI_ENC_NONE;
8519 #endif // CFG_USE_TLS
8522 case UI_ENC_STRONG: { scfgTlsStrong->set();
break; }
8523 case UI_ENC_WEAK: { scfgTlsWeak->set();
break; }
8524 default: { scfgTlsOff->set();
break; }
8527 grpAuth =
new Fl_Group(15, 255, 670, 90,
8528 S(
"Client to server authentication"));
8531 scfgAuthOff =
new Fl_Radio_Round_Button(30, 270, 640, 30,
8534 scfgAuthUser =
new Fl_Radio_Round_Button(30, 300, 640, 30,
8535 S(
"AUTHINFO USER/PASS as defined in RFC 4643"));
8539 grpAuth->align(FL_ALIGN_TOP_LEFT);
8540 grpAuth->box(FL_EMBOSSED_BOX);
8541 #if !CFG_NNTP_AUTH_UNENCRYPTED
8542 if(UI_ENC_NONE == sc->enc)
8545 grpAuth->deactivate();
8552 case UI_AUTH_USER: { scfgAuthUser->set();
break; }
8553 default: { scfgAuthOff->set();
break; }
8557 gp =
new Fl_Group(0, gy, 700, gh);
8562 new Fl_Box(0, gy, bw, gh);
8563 p =
new Fl_Button(15, y, w, h, S(
"OK"));
8564 p->callback(ok_cb, (
void*)
this);
8565 new Fl_Box(500 - bw, gy, bw, gh);
8566 p =
new Fl_Button(700 - bw + 15, y, w, h, S(
"Cancel"));
8567 p->callback(cancel_cb, (
void*)
this);
8569 bp =
new Fl_Box(bw, gy, 700 - (2 * bw), gh);
8575 resizable(scfgGroup);
8577 size_range(700, 395, 700, 395);
8579 Fl::visual(FL_DOUBLE | FL_INDEX);
8580 #endif // CFG_DB_DISABLE
8588 ServerCfgWindow::~ServerCfgWindow(
void)
8592 delete[] tls_headline;
8601 void IdentityCfgWindow::ok_cb_i(
void)
8608 len1 = std::strlen(fromName->value());
8609 len2 = std::strlen(fromEmail->value());
8612 SC(
"Do not use non-ASCII for the translation of this item")
8613 fl_message_title(S("Error"));
8614 fl_alert("%s", S("From header field element too
long"));
8616 buf = new
char[len1 + len2 + (std::
size_t) 4];
8620 if(len1) { std::strcat(buf, fromName->value()); }
8621 std::strcat(buf,
" <");
8622 std::strcat(buf, fromEmail->value());
8623 std::strcat(buf,
">");
8629 len1 = std::strlen(replytoName->value());
8630 len2 = std::strlen(replytoEmail->value());
8633 SC(
"Do not use non-ASCII for the translation of this item")
8634 fl_message_title(S("Error"));
8635 fl_alert("%s", S("Reply-To header field element too
long"));
8637 buf = new
char[len1 + len2 + (std::
size_t) 4];
8641 if(len1) { std::strcat(buf, replytoName->value()); }
8642 std::strcat(buf,
" <");
8643 std::strcat(buf, replytoEmail->value());
8644 std::strcat(buf,
">");
8654 Fl::delete_widget(
this);
8661 IdentityCfgWindow::IdentityCfgWindow(
const char* label) :
8662 UI_WINDOW_CLASS(700, 200, label)
8673 int y, w, h, gy, gh, bw;
8679 callback(cancel_cb, (
void*)
this);
8685 if(std::strlen(from_name))
8690 if(
'<' == from_name[i])
8693 if(NULL == std::strchr(&from_name[i + (std::size_t) 1], (
int)
'<'))
8696 if(!i || ((std::size_t) 1 == i &&
' ' == from_name[0]))
8700 else { from_name[i - (std::size_t) 1] = 0; }
8702 i = std::strlen(from_email) - (std::size_t) 1;
8703 if(
'>' != from_email[i]) { from_email[0] = 0; }
8704 else { from_email[i] = 0; }
8713 replyto_email[0] = 0;
8714 if(std::strlen(replyto_name))
8717 while(replyto_name[i])
8719 if(
'<' == replyto_name[i])
8721 if(!i || ((std::size_t) 1 == i &&
' ' == replyto_name[0]))
8723 replyto_name[0] = 0;
8725 else { replyto_name[i - (std::size_t) 1] = 0; }
8727 i = std::strlen(replyto_email) - (std::size_t) 1;
8728 if(
'>' != replyto_email[i]) { replyto_email[0] = 0; }
8729 else { replyto_email[i] = 0; }
8737 cfgGroup =
new Fl_Group(0, 0, 700, 200);
8741 gui_set_default_font();
8742 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
8743 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
8744 if(w1 > w2) { w = w1; }
else { w = w2; }
8745 if(h1 > h2) { h = h1; }
else { h = h2; }
8751 gp1 =
new Fl_Group(0, 0, 700, gy);
8755 fromName =
new Fl_Input(15, 35, 325, 30,
"From (Name):");
8756 fromName->align(FL_ALIGN_TOP_LEFT);
8757 fromName->value(from_name);
8759 fromEmail =
new Fl_Input(355, 35, 325, 30,
"From (e-mail):");
8760 fromEmail->align(FL_ALIGN_TOP_LEFT);
8761 fromEmail->value(from_email);
8763 replytoName =
new Fl_Input(15, 100, 325, 30,
"Reply-To (Name):");
8764 replytoName->align(FL_ALIGN_TOP_LEFT);
8765 replytoName->value(replyto_name);
8767 replytoEmail =
new Fl_Input(355, 100, 325, 30,
"Reply-To (e-mail):");
8768 replytoEmail->align(FL_ALIGN_TOP_LEFT);
8769 replytoEmail->value(replyto_email);
8771 bp =
new Fl_Box(0, 150, 700, gy - 150);
8777 gp2 =
new Fl_Group(0, gy, 700, gh);
8782 new Fl_Box(0, gy, bw, gh);
8783 p =
new Fl_Button(15, y, w, h, S(
"OK"));
8784 p->callback(ok_cb, (
void*)
this);
8785 new Fl_Box(500 - bw, gy, bw, gh);
8786 p =
new Fl_Button(700 - bw + 15, y, w, h, S(
"Cancel"));
8787 p->callback(cancel_cb, (
void*)
this);
8789 bp =
new Fl_Box(bw, gy, 700 - (2 * bw), gh);
8795 cfgGroup->resizable(gp1);
8796 resizable(cfgGroup);
8798 size_range(700, 150 + gh, 0, 0);
8800 Fl::visual(FL_DOUBLE | FL_INDEX);
8801 #endif // CFG_DB_DISABLE
8809 IdentityCfgWindow::~IdentityCfgWindow(
void)
8817 void MiscCfgWindow::ok_cb_i(
void)
8820 const unsigned int cac_limit = (
unsigned int) UI_CAC_MAX;
8825 is = cacField->value();
8826 if(NULL != is && 1 == std::sscanf(is,
"%u", &i))
8828 if(cac_limit < i) { i = cac_limit; }
8834 SC(
"Do not use non-ASCII for the translation of this item")
8835 fl_message_title(S("Error"));
8836 fl_alert("%s", S("Invalid value for CAC"));
8856 if(!error) { Fl::delete_widget(
this); }
8863 MiscCfgWindow::MiscCfgWindow(
const char* label) :
8864 UI_WINDOW_CLASS(400, 235, label)
8872 int y, w, h, gy, gh, bw;
8874 std::ostringstream ss;
8876 SC(
"Preserve the spaces at beginning and end")
8877 const
char* label_tab_cac = S(" Misc ");
8878 const
char* label_tab_qs = S(" Quote style ");
8879 SC("Preserve the colon")
8880 const
char* label_cac = S("Clamp article count threshold:");
8885 callback(cancel_cb, (
void*) this);
8888 gp1 = new Fl_Group(0, 0, 400, 235);
8892 gui_set_default_font();
8893 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
8894 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
8895 if(w1 > w2) { w = w1; }
else { w = w2; }
8896 if(h1 > h2) { h = h1; }
else { h = h2; }
8902 cfgTabs =
new Fl_Tabs(0, 0, 400, gy);
8905 cacGroup =
new Fl_Group(0, th - tg, 400, 235 - th + tg, label_tab_cac);
8908 cacField =
new Fl_Input(15, 55, 400 - 30, 30, label_cac);
8909 cacField->align(FL_ALIGN_TOP_LEFT);
8912 const std::string& s = ss.str();
8913 cacField->value(s.c_str());
8914 cmprEnable =
new Fl_Check_Button(15, 90, 400 - 30, 30,
8915 S(
"Negotiate compression if available"));
8916 cmprEnable->tooltip(
8917 SC(
"This is the tooltip for the compression negotiation checkbox")
8918 S(
"Not recommended when confidential newsgroups are accessed")
8921 #if CFG_CMPR_DISABLE
8922 cmprEnable->deactivate();
8923 #endif // CFG_CMPR_DISABLE
8924 localTime =
new Fl_Check_Button(15, 120, 400 - 30, 30,
8925 S(
"Use localtime for Date header field"));
8927 SC(
"This is the tooltip for the use localtime checkbox")
8928 S(
"Using localtime is recommended by RFC 5322")
8931 uagentEnable =
new Fl_Check_Button(15, 150, 400 - 30, 30,
8932 S(
"Add User-Agent header field"));
8935 bp =
new Fl_Box(0, 180, 400, gy - 150);
8939 cacGroup->resizable(bp);
8943 qsGroup =
new Fl_Group(0, th - tg, 400, 235 - th + tg, label_tab_qs);
8946 qsSpace =
new Fl_Check_Button(15, 45, 400 - 30, 30,
8947 S(
"Space after quote marks"));
8949 qsUnify =
new Fl_Check_Button(15, 75, 400 - 30, 30,
8950 S(
"Unify quote marks for follow-up"));
8953 bp =
new Fl_Box(0, 150, 400, gy - 150);
8957 qsGroup->resizable(bp);
8960 cfgTabs->resizable(cacGroup);
8962 gp2 =
new Fl_Group(0, gy, 400, gh);
8967 new Fl_Box(0, gy, bw, gh);
8968 p =
new Fl_Button(15, y, w, h, S(
"OK"));
8969 p->callback(ok_cb, (
void*)
this);
8970 new Fl_Box(500 - bw, gy, bw, gh);
8971 p =
new Fl_Button(400 - bw + 15, y, w, h, S(
"Cancel"));
8972 p->callback(cancel_cb, (
void*)
this);
8974 bp =
new Fl_Box(bw, gy, 400 - (2 * bw), gh);
8980 gp1->resizable(cfgTabs);
8983 size_range(400, 235, 0, 0);
8985 Fl::visual(FL_DOUBLE | FL_INDEX);
8986 #endif // CFG_DB_DISABLE
8994 MiscCfgWindow::~MiscCfgWindow(
void)
9002 void SearchWindow::ok_cb_i(
void)
9011 ss = searchField->value();
9017 SC(
"Do not use non-ASCII for the translation of this item")
9018 fl_message_title(S("Error"));
9019 fl_alert("%s", S("Processing Unicode
data in search
string failed"));
9023 if(std::strcmp(*currentSearchString, ss_nfc))
9026 tmp = std::strlen(ss_nfc);
9027 if((std::size_t) INT_MAX <= tmp) { len = INT_MAX - 1; }
9028 else { len = (int) tmp; }
9030 delete[] *currentSearchString;
9031 p =
new char[len + 1];
9032 std::strncpy(p, ss_nfc, (
size_t) len);
9034 *currentSearchString = p;
9037 if(ss != ss_nfc) {
enc_free((
void*) ss_nfc); }
9048 SearchWindow::SearchWindow(
const char* label,
const char** oldSearchString) :
9049 UI_WINDOW_CLASS(400, 165, label)
9052 Fl_Group* searchGroup;
9053 Fl_Group* searchGroup2;
9054 Fl_Group* buttonGroup;
9057 int y, w, h, gy, gh, bw;
9059 std::ostringstream ss;
9061 SC(
"Preserve the colon")
9062 const
char* label_search = S("Search for:");
9068 currentSearchString = oldSearchString;
9073 callback(cancel_cb, (
void*) this);
9076 gp = new Fl_Group(0, 0, 400, 165);
9080 gui_set_default_font();
9081 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
9082 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
9083 if(w1 > w2) { w = w1; }
else { w = w2; }
9084 if(h1 > h2) { h = h1; }
else { h = h2; }
9089 searchGroup =
new Fl_Group(0, 0, 400, 165 - gh);
9090 searchGroup->begin();
9093 searchGroup2 =
new Fl_Group(0, 0, 400, 80);
9094 searchGroup2->begin();
9097 searchField =
new Fl_Input(15, 35, 400 - 30, 30, label_search);
9098 searchField->align(FL_ALIGN_TOP_LEFT);
9100 ss << *currentSearchString << std::flush;
9101 const std::string& s = ss.str();
9102 searchField->value(s.c_str());
9104 #if defined FL_ABI_VERSION && 10400 <= FL_ABI_VERSION
9107 #else // defined FL_ABI_VERSION && 10303 <= FL_ABI_VERSION
9109 #endif // defined FL_ABI_VERSION && 10303 <= FL_ABI_VERSION
9110 (searchField->size(), 0);
9111 searchField->take_focus();
9113 searchGroup2->end();
9115 cisEnable =
new Fl_Check_Button(15, 80, 400 - 30, 30,
9116 S(
"Search case-insensitive"));
9118 cisEnable->clear_visible_focus();
9120 bp =
new Fl_Box(0, 110, 400, gy - 110);
9125 searchGroup->resizable(bp);
9127 buttonGroup =
new Fl_Group(0, gy, 400, gh);
9128 buttonGroup->begin();
9132 new Fl_Box(0, gy, bw, gh);
9133 p =
new Fl_Button(15, y, w, h, S(
"OK"));
9134 p->callback(ok_cb, (
void*)
this);
9135 p->shortcut(FL_Enter);
9136 p->clear_visible_focus();
9137 new Fl_Box(400 - bw, gy, bw, gh);
9138 p =
new Fl_Button(400 - bw + 15, y, w, h, S(
"Cancel"));
9139 p->callback(cancel_cb, (
void*)
this);
9140 p->shortcut(FL_Escape);
9141 p->clear_visible_focus();
9143 bp =
new Fl_Box(bw, gy, 400 - (2 * bw), gh);
9148 buttonGroup->resizable(bp);
9151 gp->resizable(searchGroup);
9154 size_range(400, 165, 0, 0);
9156 Fl::visual(FL_DOUBLE | FL_INDEX);
9157 #endif // CFG_DB_DISABLE
9165 SearchWindow::~SearchWindow(
void)
9179 const char* MIMEContent::createMessageHeader(
const char* message,
9182 const char* res = NULL;
9195 tb.append(
"[Invalid MIME message/rfc822 content]");
9201 tb.append(S(
"From"));
9203 tb.append(hdr->
from);
9207 tb.append(S(
"Subject"));
9213 tb.append(S(
"Date"));
9218 tb.append(
"[Missing or invalid header field]");
9227 tb.append(S(
"Message-ID"));
9232 tb.append(
"[Missing or invalid header field]");
9236 tb.append(hdr->
msgid);
9241 tb.append(S(
"Newsgroups"));
9245 if(!i && !hdr->
groups[0][0])
9248 tb.append(
"[Missing or invalid header field]");
9253 if(i) { tb.append(
","); }
9254 tb.append(hdr->
groups[i++]);
9264 std::free((
void*) p);
9278 MIMEContent::MIMEContentListElement*
9279 MIMEContent::decodeElement(
const char* p, std::size_t len,
char* boundary,
9280 bool alt,
bool digest, std::size_t* count)
9282 MIMEContentListElement* res = NULL;
9283 MIMEContentListElement* cle = NULL;
9284 MIMEContentListElement* ble = NULL;
9286 MIMEContentListElement* mle = NULL;
9288 MIMEContentListElement* lle = NULL;
9290 std::size_t bae = 0;
9291 std::size_t num = 0;
9299 bool message_rfc822;
9304 MIMEContentListElement* tmp;
9309 if(!std::strlen(boundary))
9311 printf(
"%s: %svvv Extract MIME encapsulated message vvv\n",
9316 printf(
"%s: %s--- Split MIME multipart entity ---\n",
9319 printf(
"%s: %sSize of body: %lu octets\n",
9322 if(!std::strlen(boundary))
9330 for(i = 0; i < num; ++i)
9333 nested_multi =
false;
9335 nested_digest =
false;
9336 message_rfc822 =
false;
9343 PRINT_ERROR(
"Invalid entity in MIME multipart entity");
9366 message_rfc822 =
true;
9375 printf(
"%s: %sContent-Type: Text (using default)\n",
9380 printf(
"%s: %sContent-Type: Message (using default)\n",
9387 message_rfc822 =
false;
9390 if(ENC_CTE_UNKNOWN == cte)
9392 PRINT_ERROR(
"Unknown MIME Content-Transfer-Encoding");
9411 printf(
"%s: %sContent-Type: Text\n",
9415 if(ENC_CS_UNKNOWN == ct.
charset)
9432 printf(
"%s: %sContent-Type: Image, Audio or Video\n",
9442 printf(
"%s: %sContent-Type: Multipart (nested)\n",
9445 nested_multi =
true;
9452 nested_digest =
true;
9460 printf(
"%s: %sContent-Type: Message\n",
9465 message_rfc822 =
true;
9479 printf(
"%s: %sContent-Type not supported\n",
9500 && ENC_CTE_UNKNOWN != cte))
9512 cle = decodeElement(p, e_len,
9513 nested_boundary, nested_alt, nested_digest, &ae);
9516 else if(message_rfc822)
9519 nested_boundary[0] = 0;
9520 mle = decodeElement(p, e_len,
9521 nested_boundary, nested_alt, nested_digest, &ae);
9528 q = createMessageHeader(p, len);
9529 cle = initElement(q, std::strlen(q), cte, &ct, e_h);
9535 SC(
"Control characters for line break at the end must stay in place")
9536 q = S("End of encapsulated message.\r\n");
9537 mle = initElement(q, std::strlen(q), cte, &ct, e_h);
9541 while(NULL != tmp->next) { tmp = tmp->next; }
9547 cle = initElement(p, e_len, cte, &ct, e_h);
9552 PRINT_ERROR(
"Decoding MIME multipart message failed");
9565 if(!i) { res = cle; }
else { lle->next = cle; }
9568 while(NULL != lle->next) { lle = lle->next; }
9587 if(std::strlen(boundary))
9589 printf(
"%s: %s--- End of MIME multipart entity ---\n",
9594 printf(
"%s: %s^^^ End of MIME encapsulated message ^^^\n",
9606 MIMEContent::MIMEContentListElement*
9607 MIMEContent::initElement(
const char* body, std::size_t body_len,
9611 MIMEContentListElement* cle =
new MIMEContentListElement;
9614 bool headerPresent =
false;
9620 std::memcpy((
void*) &cle->ct, (
void*) ct,
sizeof(
enc_mime_ct));
9623 cp =
new char[body_len + (std::size_t) 1];
9624 std::strncpy(cp, body, body_len); cp[body_len] = 0;
9628 cle->type = ENC_CD_INLINE;
9629 cle->filename = NULL;
9632 if(NULL != hdr && NULL != hdr->
mime_cte)
9634 tb.append(S(
"Transfer-Encoding"));
9638 headerPresent =
true;
9640 if(NULL != hdr && NULL != hdr->
mime_ct)
9642 tb.append(S(
"Content-Type"));
9646 headerPresent =
true;
9648 if(NULL != hdr && NULL != hdr->
mime_cd)
9650 tb.append(S(
"Content-Disposition"));
9654 headerPresent =
true;
9660 cle->header = tb.text();
9692 "with missing MIME-Version header field");
9708 if(ENC_CTE_UNKNOWN == cte)
9727 if(ENC_CS_UNKNOWN == ct.
charset)
9771 partList = initElement(p, std::strlen(p), cte, &ct, h);
9778 partList = decodeElement(p, std::strlen(p),
9779 boundary, alt, digest, &partNum);
9787 MIMEContent::~MIMEContent(
void)
9789 MIMEContentListElement* cle = partList;
9790 MIMEContentListElement* nle;
9796 std::free((
void*) cle->header);
9797 delete[] cle->content;
9807 void SubscribeWindow::ok_cb_i(
void)
9809 Fl_Tree_Item* i = subscribeTree->first_selected_item();
9816 subscribeTree->showroot(0);
9819 mainWindow->groupStateExport();
9823 if(
'\0' != ((
const char*) i->user_data())[0])
9826 name = (
char*) i->user_data();
9832 rv = subscribeTree->item_pathname(buf, 1024, i);
9837 if(-2 == rv) {
PRINT_ERROR(
"Group name too long and ignored"); }
9844 {
if(
'/' == name[ii]) { name[ii] =
'.'; } }
9851 PRINT_ERROR(
"Updating list of subscribed groups failed");
9855 i = subscribeTree->next_selected_item(i);
9862 SC(
"Do not use non-ASCII for the translation of this item")
9863 fl_message_title(S("Error"));
9864 fl_alert("%s", S("Error while updating subscribed group database"));
9866 else {
UI_STATUS(S(
"Subscribed groups stored.")); }
9870 if(NULL != mainWindow)
9873 mainWindow->groupListImport();
9877 Fl::delete_widget(
this);
9884 SubscribeWindow::SubscribeWindow(
const char* label,
core_groupdesc* glist,
9886 UI_WINDOW_CLASS(730, 350, label), grouplist(glist), grouplabels(labels)
9891 int y, w, h, gy, gh, bw;
9896 callback(cancel_cb, (
void*)
this);
9903 subscribeGroup =
new Fl_Group(0, 0, 730, 350);
9904 subscribeGroup->begin();
9907 gui_set_default_font();
9908 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
9909 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
9910 if(w1 > w2) { w = w1; }
else { w = w2; }
9911 if(h1 > h2) { h = h1; }
else { h = h2; }
9917 subscribeTree =
new Fl_Tree(0, 0, 730, 350 - gh);
9920 subscribeTree->item_labelfgcolor(FL_FOREGROUND_COLOR);
9922 subscribeTree->root()->labelfgcolor(FL_FOREGROUND_COLOR);
9923 subscribeTree->root_label(
"Usenet");
9924 subscribeTree->margintop(5);
9925 subscribeTree->marginleft(0);
9926 subscribeTree->openchild_marginbottom(5);
9927 subscribeTree->selectmode(FL_TREE_SELECT_MULTI);
9928 subscribeTree->sortorder(FL_TREE_SORT_ASCENDING);
9929 subscribeTree->callback(tree_cb, (
void*)
this);
9931 gp =
new Fl_Group(0, gy, 730, gh);
9936 new Fl_Box(0, gy, bw, gh);
9937 p =
new Fl_Button(15, y, w, h, S(
"OK"));
9938 p->callback(ok_cb, (
void*)
this);
9939 new Fl_Box(730 - bw, gy, bw, gh);
9940 p =
new Fl_Button(730 - bw + 15, y, w, h, S(
"Cancel"));
9941 p->callback(cancel_cb, (
void*)
this);
9943 bp =
new Fl_Box(bw, gy, 730 - (2 * bw), gh);
9948 subscribeGroup->end();
9949 subscribeGroup->resizable(subscribeTree);
9950 resizable(subscribeGroup);
9956 size_range(2 * bw, 100, 0, 0);
9958 Fl::visual(FL_DOUBLE | FL_INDEX);
9959 #endif // CFG_DB_DISABLE
9967 SubscribeWindow::~SubscribeWindow(
void)
9977 void ProtocolConsole::update(
void)
9980 const char* logname;
9992 logfp = fopen(logname,
"r");
9993 log_free((
void*) logname); logname = NULL;
9997 protocolConsole->consoleDisplay->insert(
9998 S(
"Logfile is only available in debug mode.") );
9999 protocolConsole->consoleDisplay->insert(
"\n");
10000 protocolConsole->consoleDisplay->insert(
10001 S(
"Use command line option -debug for debug mode.") );
10007 while(!feof(logfp))
10009 for(n = 0; n <
sizeof(buffer) - 1; ++n)
10012 if(EOF == rv) {
break; }
10016 if(0x0D == rv) { buffer[n] = 0x20; }
10017 else { buffer[n] = (char) (
unsigned char) rv; }
10021 protocolConsole->consoleDisplay->insert(buffer);
10026 if(NULL == protocolConsole) {
break; }
10028 if(protocolConsole) { clearerr(logfp); }
10037 ProtocolConsole::ProtocolConsole(
const char* label) :
10038 UI_WINDOW_CLASS(730, 395, label), logfp(NULL), nolog(0)
10041 consoleText =
new Fl_Text_Buffer();
10042 consoleDisplay =
new Fl_Text_Display(0, 0, 730, 395);
10043 consoleDisplay->buffer(consoleText);
10044 resizable(consoleDisplay);
10045 callback(exit_cb, (
void*)
this);
10046 #if !CFG_DB_DISABLE
10047 Fl::visual(FL_DOUBLE | FL_INDEX);
10048 #endif // CFG_DB_DISABLE
10056 ProtocolConsole::~ProtocolConsole(
void)
10058 if(logfp) { fclose(logfp); }
10061 delete consoleDisplay;
10062 delete consoleText;
10064 protocolConsole = NULL;
10071 void MIDSearchWindow::ok_cb_i(
void)
10073 std::size_t limit = 248;
10074 const char* message_id = mid->value();
10080 len = std::strlen(message_id);
10081 buf =
new char[len + (std::size_t) 1];
10082 std::strcpy(buf, message_id);
10086 while(0x09 == (
int) p[0] ||
' ' == p[0] ||
'<' == p[0])
10091 while(0x09 == (
int) p[len - (std::size_t) 1]
10092 ||
' ' == p[len - (std::size_t) 1] ||
'>' == p[len - (std::size_t) 1])
10094 p[len - (std::size_t) 1] = 0;
10101 SC(
"Do not use non-ASCII for the translation of this item")
10102 fl_message_title(S("Error"));
10104 S("Message-ID too
long\nLimit is 250 characters, including angle brackets"));
10108 Fl::delete_widget(this);
10111 mainWindow->viewArticle(UI_CB_START, (const
char*) p);
10119 MIDSearchWindow::MIDSearchWindow(const
char* label) :
10120 UI_WINDOW_CLASS(700, 150, label)
10126 int y, w, h, gy, gh, bw;
10127 int w1, w2, h1, h2;
10132 callback(cancel_cb, (
void*)
this);
10135 cfgGroup =
new Fl_Group(0, 0, 700, 150);
10139 gui_set_default_font();
10140 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
10141 fl_measure(S(
"OK"), w2 = 0, h2 = 0);
10142 if(w1 > w2) { w = w1; }
else { w = w2; }
10143 if(h1 > h2) { h = h1; }
else { h = h2; }
10149 gp1 =
new Fl_Group(0, 0, 700, gy);
10153 mid =
new Fl_Input(15, 35, 670, 30,
"Message-ID:");
10154 mid->align(FL_ALIGN_TOP_LEFT);
10156 bp =
new Fl_Box(0, 100, 700, gy - 100);
10160 gp1->resizable(bp);
10162 gp2 =
new Fl_Group(0, gy, 700, gh);
10167 new Fl_Box(0, gy, bw, gh);
10168 p =
new Fl_Return_Button(15, y, w, h, S(
"OK"));
10169 p->callback(ok_cb, (
void*)
this);
10170 new Fl_Box(500 - bw, gy, bw, gh);
10171 p =
new Fl_Button(700 - bw + 15, y, w, h, S(
"Cancel"));
10172 p->callback(cancel_cb, (
void*)
this);
10173 p->shortcut(FL_Escape);
10176 bp =
new Fl_Box(bw, gy, 700 - (2 * bw), gh);
10179 gp2->resizable(bp);
10182 cfgGroup->resizable(gp1);
10183 resizable(cfgGroup);
10185 size_range(700, 100 + gh, 0, 0);
10186 #if !CFG_DB_DISABLE
10187 Fl::visual(FL_DOUBLE | FL_INDEX);
10188 #endif // CFG_DB_DISABLE
10196 MIDSearchWindow::~MIDSearchWindow(
void)
10204 BugreportWindow::BugreportWindow(
const char* label,
const char* content) :
10205 UI_WINDOW_CLASS(795, 395, label)
10210 len = std::strlen(content);
10211 if(INT_MAX < len) { len = 0; }
10212 bugreportText =
new Fl_Text_Buffer((
int) ++len, 0);
10213 bugreportText->insert(0, content);
10214 bugreportDisplay =
new Fl_Text_Display(0, 0, 795, 395);
10215 bugreportDisplay->textfont(FL_COURIER);
10216 bugreportDisplay->buffer(bugreportText);
10217 resizable(bugreportDisplay);
10218 callback(exit_cb, (
void*)
this);
10219 #if !CFG_DB_DISABLE
10220 Fl::visual(FL_DOUBLE | FL_INDEX);
10221 #endif // CFG_DB_DISABLE
10229 BugreportWindow::~BugreportWindow(
void)
10232 delete bugreportDisplay;
10233 delete bugreportText;
10240 MotdWindow::MotdWindow(
const char* motd,
const char* label) :
10241 UI_WINDOW_CLASS(795, 395, label)
10244 motdText =
new Fl_Text_Buffer();
10245 motdText->text(motd);
10246 motdDisplay =
new Fl_Text_Display(0, 0, 795, 395);
10247 motdDisplay->textfont(FL_COURIER);
10248 motdDisplay->buffer(motdText);
10249 resizable(motdDisplay);
10250 callback(exit_cb, (
void*)
this);
10251 #if !CFG_DB_DISABLE
10252 Fl::visual(FL_DOUBLE | FL_INDEX);
10253 #endif // CFG_DB_DISABLE
10261 MotdWindow::~MotdWindow(
void)
10264 delete motdDisplay;
10272 LicenseWindow::LicenseWindow(
const char* label) :
10273 UI_WINDOW_CLASS(795, 395, label)
10278 licenseText =
new Fl_Text_Buffer();
10279 rv = licenseText->loadfile(CFG_LICENSE_PATH
"/license.txt");
10280 if(rv) { licenseText->insert(0, S(
"Error: License file not found")); }
10281 licenseDisplay =
new Fl_Text_Display(0, 0, 795, 395);
10282 licenseDisplay->textfont(FL_COURIER);
10283 licenseDisplay->buffer(licenseText);
10284 resizable(licenseDisplay);
10285 callback(exit_cb, (
void*)
this);
10286 #if !CFG_DB_DISABLE
10287 Fl::visual(FL_DOUBLE | FL_INDEX);
10288 #endif // CFG_DB_DISABLE
10296 LicenseWindow::~LicenseWindow(
void)
10299 delete licenseDisplay;
10300 delete licenseText;
10309 return(gui_print_header_fields(h));
10316 void ArticleWindow::articleUpdate(Fl_Text_Buffer* article)
10319 const char* url[] = {
"http://",
"https://",
"ftp://",
"nntp://",
10320 "news:",
"mailto:", NULL };
10321 const std::size_t url_len[] = { 7, 8, 6, 7, 5, 7 };
10322 const char bold =
'A';
10323 const char sig =
'B';
10324 const char cit =
'C';
10325 const char link =
'D';
10326 const char plain =
'E';
10327 const char l1 =
'F';
10328 const char l2 =
'G';
10329 const char l3 =
'H';
10330 const char l4 =
'I';
10334 std::size_t ii = 0;
10335 std::size_t iii = 0;
10340 bool ready =
false;
10342 bool delim =
false;
10343 bool signature =
false;
10344 bool citation =
false;
10345 bool hyperlink =
false;
10346 std::size_t cl = 0;
10347 bool cl_lock =
false;
10352 if(NULL == article)
10354 PRINT_ERROR(
"Article display request without content ignored (bug)");
10357 gui_check_article(article);
10358 articleText = article;
10359 articleDisplay->buffer(articleText);
10361 #if !UI_AW_REFERENCES
10363 if (1 == articleText->findchar_forward(0, 0x1DU, &pos))
10365 articleText->remove(articleText->line_start(pos),
10366 articleText->line_end(pos) + 1);
10368 #endif // ! UI_AW_REFERENCES
10371 gui_process_shy(articleText);
10374 style = articleText->text();
10375 if(NULL == style) { len = 0; }
10376 else { len = std::strlen(style); }
10377 if(INT_MAX < len) { len = INT_MAX; }
10378 for(i = 0; i < len; ++i)
10380 if(
'\n' == style[i])
10395 if(
' ' == c || 0x09 == (
int) c ||
'>' == c ||
'"' == c)
10401 if(sol && (
'|' == style[i] ||
'!' == style[i]))
10403 if(!hyperlink) { citation =
true; }
10406 if(sol) { sol =
false; delim =
true; ss = 0; cl = 0; ii = 0; }
10411 if(
'|' == style[i])
10415 for(iiii = i - ii; iiii < i; ++iiii)
10417 if(
'_' != articleText->byte_at((
int) iiii)) {
break; }
10421 for(iiii = 0; iiii <= ii; ++iiii)
10423 style[i - iiii] = plain;
10435 if(
'_' != style[i]) { hs = bold; }
else { hs = plain; }
10438 if(
'|' == style[i] && 79U <= iii) { ready =
true; }
10439 else if(
'_' == style[i]) { ++iii; }
10440 if(
':' == style[i]) { hs = plain; }
10446 if(
'-' == style[i] && !ii) { ss = 1; }
10447 if(
'-' == style[i] && 1U == ii && 1 == ss) { ss = 2; }
10448 if(
' ' == style[i] && 2U == ii && 2 == ss)
10451 if((
char) 0x0A == style[i + 1U])
10453 if(gui_last_sig_separator(&style[i + 1U]))
10455 style[i] = sig; style[i - 1U] = sig; style[i - 2U] = sig;
10462 while(NULL != url[url_i])
10464 if(!std::strncmp(&style[i], url[url_i], url_len[url_i]))
10476 if(
' ' == c || 0x09 == (
int) c ||
'<' == c ||
'"' == c)
10480 else { delim =
false; }
10486 if(
'>' == style[i]) { cl_lock =
false; }
10487 else { cl_lock =
true; }
10489 if(
'>' == style[i] && !cl_lock) { ++cl; }
10490 if(
'>' != style[i] &&
' ' != style[i] && (
char) 9 != style[i])
10494 if(4U < cl) { cl = 1; }
10497 case 1: { style[i] = l1;
break; }
10498 case 2: { style[i] = l2;
break; }
10499 case 3: { style[i] = l3;
break; }
10500 case 4: { style[i] = l4;
break; }
10501 default: { style[i] = plain;
break; }
10506 if(signature) { style[i] = sig; }
10507 if(citation && !signature) { style[i] = cit; }
10508 if(hyperlink) { style[i] = link; }
10511 articleStyle =
new Fl_Text_Buffer((
int) len, 0);
10512 if(NULL != style) { articleStyle->text(style); }
10513 std::free((
void*) style);
10516 articleDisplay->highlight_data(articleStyle, styles, styles_len,
'A', NULL,
10520 if (1 == articleText->findchar_forward(0, 0x1DU, &pos))
10522 articleText->replace(pos, pos + 1,
" ");
10530 ArticleWindow::ArticleWindow(
const char* article,
const char* label) :
10531 UI_WINDOW_CLASS(795, 395, label)
10542 FL_FOREGROUND_COLOR,
10548 FL_FOREGROUND_COLOR,
10556 Fl_Button* buttonp;
10557 int y, w, h, gy, gh, bw;
10561 const char* q = NULL;
10562 Fl_Text_Buffer* tb;
10563 const char* hdr = NULL;
10572 articleText = NULL;
10573 articleStyle = NULL;
10588 raw =
new char[std::strlen(article) + (std::size_t) 1];
10589 std::strcpy(raw, article);
10592 eoh = std::strstr(raw,
"\r\n\r\n");
10597 SC(
"Do not use non-ASCII for the translation of this item")
10598 fl_message_title(S("Error"));
10599 fl_alert("%s", S("Processing of article failed"));
10607 tb =
new Fl_Text_Buffer(0, 0);
10609 hdr = printHeaderFields(alt_hier->
child[0]->
header);
10619 mimeData =
new MIMEContent(alt_hier->
child[0]->
header, q);
10621 gui_decode_mime_entities(tb, mimeData,
10625 callback(cancel_cb, (
void*)
this);
10632 articleGroup =
new Fl_Group(0, 0, 795, 395);
10633 articleGroup->begin();
10636 gui_set_default_font();
10637 fl_measure(S(
"Cancel"), w = 0, h = 0);
10643 articleDisplay =
new My_Text_Display(0, 0, 795, 395 - gh);
10644 articleDisplay->textfont(FL_COURIER);
10647 styles =
new Fl_Text_Display::Style_Table_Entry[styles_len];
10648 styles[0].color = FL_FOREGROUND_COLOR;
10649 styles[0].font = FL_COURIER_BOLD;
10650 styles[0].size = articleDisplay->textsize();
10651 styles[0].attr = 0;
10652 for(ii = 1; ii < styles_len; ++ii)
10654 styles[ii].color = styles_colors[ii];
10655 styles[ii].font = articleDisplay->textfont();
10656 styles[ii].size = articleDisplay->textsize();
10657 styles[ii].attr = 0;
10661 resizable(articleDisplay);
10663 gp =
new Fl_Group(0, gy, 795, gh);
10668 new Fl_Box(0, gy, bw, gh);
10669 new Fl_Box(795 - bw, gy, bw, gh);
10670 buttonp =
new Fl_Button(795 - bw + 15, y, w, h, S(
"Cancel"));
10671 buttonp->callback(cancel_cb, (
void*)
this);
10673 bp =
new Fl_Box(bw, gy, 795 - (2 * bw), gh);
10678 articleGroup->end();
10679 articleGroup->resizable(articleDisplay);
10680 resizable(articleGroup);
10686 size_range(2 * bw, 100, 0, 0);
10687 #if !CFG_DB_DISABLE
10688 Fl::visual(FL_DOUBLE | FL_INDEX);
10689 #endif // CFG_DB_DISABLE
10699 ArticleWindow::~ArticleWindow(
void)
10701 if(NULL != mimeData) {
delete mimeData; }
10703 articleDisplay->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
10704 if(articleStyle)
delete articleStyle;
10705 if(styles) {
delete[] styles; }
10706 articleDisplay->buffer(dummyTb);
10707 if(articleText)
delete articleText;
10716 void ArticleSrcWindow::save_cb_i(
void)
10720 SC(
"Do not use characters for the translation that cannot be")
10721 SC("converted to the ISO 8859-1 character set for this item.")
10722 SC("Leave the original
string in place if in doubt.")
10723 const
char* title = S("Save article source code");
10726 fl_file_chooser_ok_label(S("Save"));
10727 if(NULL != suggested_pathname)
10729 pathname = fl_file_chooser(title,
"*", suggested_pathname, 0);
10730 if(NULL != pathname)
10733 rv = gui_check_pathname(pathname);
10740 SC(
"Do not use non-ASCII for the translation of this item")
10741 fl_message_title(S("Error"));
10742 fl_alert("%s", S("Operation failed"));
10754 ArticleSrcWindow::ArticleSrcWindow(const
char* article, const
char* label) :
10755 UI_WINDOW_CLASS(795, 395, label)
10760 int y, w, h, gy, gh, bw;
10761 int w1, w2, h1, h2;
10763 const char* ap = NULL;
10766 unsigned int octet;
10774 len = std::strlen(article);
10775 srcArticle =
new char[++len];
10776 std::strcpy(srcArticle, article);
10780 srcText =
new Fl_Text_Buffer();
10781 srcStyle =
new Fl_Text_Buffer();
10783 if(NULL == ap) { srcText->insert(0,
"Conversion to POSIX form failed"); }
10786 srcText->insert(0, ap);
10788 buflen = srcText->length();
10791 srcStyle->insert(i,
"A");
10792 octet = (
unsigned int) (
unsigned char) srcText->byte_at(i);
10793 num[0] = (char) (
unsigned char) octet;
10796 || 0x09U == octet )
10799 srcText->replace(i, i + 1, num);
10800 if(!toggle) { style =
"BB"; }
else { style =
"CC"; }
10801 srcStyle->replace(i, i + 1, style);
10802 buflen = srcText->length();
10806 else { toggle = 0; }
10810 gui_check_article(srcText);
10814 callback(cancel_cb, (
void*)
this);
10821 srcGroup =
new Fl_Group(0, 0, 795, 395);
10825 gui_set_default_font();
10826 fl_measure(S(
"Cancel"), w1 = 0, h1 = 0);
10827 fl_measure(S(
"Save"), w2 = 0, h2 = 0);
10828 if(w1 > w2) { w = w1; }
else { w = w2; }
10829 if(h1 > h2) { h = h1; }
else { h = h2; }
10835 srcDisplay =
new Fl_Text_Display(0, 0, 795, 395 - gh);
10836 srcDisplay->textfont(FL_COURIER);
10837 srcDisplay->buffer(srcText);
10838 resizable(srcDisplay);
10840 styles =
new Fl_Text_Display::Style_Table_Entry[3];
10841 styles[0].color = FL_FOREGROUND_COLOR;
10842 styles[0].font = FL_COURIER;
10843 styles[0].size = srcDisplay->textsize();
10844 styles[0].attr = 0;
10845 styles[1].color = FL_COLOR_CUBE + (Fl_Color) 35;
10846 styles[1].font = FL_COURIER;
10847 styles[1].size = srcDisplay->textsize();
10848 styles[1].attr = 0;
10849 styles[2].color = FL_RED;
10850 styles[2].font = FL_COURIER;
10851 styles[2].size = srcDisplay->textsize();
10852 styles[2].attr = 0;
10853 srcDisplay->highlight_data(srcStyle, styles, 3,
'A', NULL, NULL);
10855 gp =
new Fl_Group(0, gy, 795, gh);
10860 new Fl_Box(0, gy, bw, gh);
10861 p =
new Fl_Button(15, y, w, h, S(
"Save"));
10862 p->callback(save_cb, (
void*)
this);
10863 new Fl_Box(795 - bw, gy, bw, gh);
10864 p =
new Fl_Button(795 - bw + 15, y, w, h, S(
"Cancel"));
10865 p->callback(cancel_cb, (
void*)
this);
10867 bp =
new Fl_Box(bw, gy, 795 - (2 * bw), gh);
10873 srcGroup->resizable(srcDisplay);
10874 resizable(srcGroup);
10880 size_range(2 * bw, 100, 0, 0);
10881 #if !CFG_DB_DISABLE
10882 Fl::visual(FL_DOUBLE | FL_INDEX);
10883 #endif // CFG_DB_DISABLE
10891 ArticleSrcWindow::~ArticleSrcWindow(
void)
10894 srcDisplay->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
10897 srcDisplay->buffer(dummyTb);
10899 delete[] srcArticle;
10912 int ComposeWindow::searchHeaderField(
const char* name,
int* start,
int* end)
10916 unsigned int c = (
unsigned int)
'\n';
10921 rv = compHeader->search_forward(sp, name, start, 1);
10925 if(0 < *start) { c = compHeader->char_at(*start - 1); }
10926 if((
unsigned int)
'\n' != c)
10935 rv = compHeader->findchar_forward(*start, (
unsigned int)
'\n', end);
10936 if(1 == rv) { res = 0; }
10940 if((
unsigned int)
' ' == compHeader->char_at(*end + 1)
10941 && (
unsigned int)
'\n' != compHeader->char_at(*end + 2))
10943 rv = compHeader->findchar_forward(*end + 1,
10944 (
unsigned int)
'\n', end);
10945 if(1 != rv) { res = -1; }
10971 const char* ComposeWindow::extractHeaderField(
const char* name)
10979 rv = searchHeaderField(name, &start, &end);
10983 rv = compHeader->search_forward(start,
": ", &pos, 1);
10987 res = compHeader->text_range(pos, end);
11004 int ComposeWindow::replaceHeaderField(
const char* name,
const char* new_body)
11012 rv = searchHeaderField(name, &start, &end);
11016 rv = compHeader->search_forward(start,
": ", &pos, 1);
11023 compHeader->replace(pos, end, new_body);
11040 void ComposeWindow::deleteHeaderField(
const char* name)
11046 rv = searchHeaderField(name, &start, &end);
11047 if(!rv) { compHeader->remove(start, end + 1); }
11060 int ComposeWindow::checkArticleBody(
const char* body)
11064 const char* sig_delim;
11065 const char* sig = NULL;
11069 bool check =
false;
11070 std::size_t
lines = 0;
11075 len = std::strlen(body);
11080 sig_delim = std::strstr(p,
"\n-- \n");
11081 if(NULL == sig_delim) {
break; }
11082 else { sig = p = &sig_delim[1]; }
11084 if(NULL != sig) { len = (std::size_t) (sig - body); }
11086 for(i = 0; i < len; ++i)
11088 if(0x0A == (
int) body[i]) { sol =
true; check =
false;
continue; }
11089 if(sol) { ++
lines; }
11090 if(sol &&
'>' != body[i]) { check =
true; }
11096 if(
' ' != body[i] && 0x09 != (
int) body[i]) { res = 0;
break; }
11100 if(res && (std::size_t) 1 >=
lines &&
'>' != body[0]) { res = 0; }
11110 void ComposeWindow::change_cb_i(
void)
11113 const char* subject_new;
11116 std::size_t len = 8;
11119 subject = subjectField->value();
11121 subject_new = fl_input(
"%s",
"", S(
"New subject:"));
11122 if(NULL != subject_new)
11124 if(std::strlen(subject_new))
11128 q = std::strstr(
subject,
" (was: ");
11132 len += std::strlen(subject_new) + std::strlen(q);
11133 p =
new char[++len];
11134 std::strcpy(p, subject_new);
11136 subjectField->value(p);
11143 q = std::strstr(
subject,
"Re: ");
11145 len += std::strlen(subject_new) + std::strlen(
subject);
11146 p =
new char[++len];
11147 std::strcpy(p, subject_new);
11148 std::strcat(p,
" (was: ");
11150 std::strcat(p,
")");
11151 subjectField->value(p);
11162 void ComposeWindow::style_update_cb_i(
int pos,
int nInserted,
int nDeleted,
11163 Fl_Text_Buffer* style,
11164 Fl_Text_Editor* editor)
11174 std::size_t p72, p78;
11177 if(0 > nInserted || 0 > nDeleted)
11179 PRINT_ERROR(
"Invalid parameter in compose window style update CB");
11184 if(!nInserted && !nDeleted) {
return; }
11192 buf =
new char[(std::size_t) (nInserted + 1)];
11194 else { buf = sbuf; }
11195 std::memset((
void*) buf,
'A', (std::size_t) nInserted);
11196 buf[nInserted] = 0;
11197 style->replace(pos, pos + nDeleted, buf);
11202 style->remove(pos, pos + nDeleted);
11206 start = editor->buffer()->line_start(pos);
11207 end = editor->buffer()->line_end(pos + nInserted);
11208 lines = 1 + editor->buffer()->count_lines(pos, end);
11209 for(i = 0; i <
lines; ++i)
11211 buf = editor->buffer()->line_text(start);
11212 if(NULL == buf) {
continue; }
11213 len = std::strlen(buf);
11216 std::memset((
void*) buf,
'A', len);
11222 while((std::size_t) next - (std::size_t) start < len)
11224 if(72 == pil) { p72 = (std::size_t) next - (std::size_t) start; }
11225 if(78 == pil++) { p78 = (std::size_t) next - (std::size_t) start; }
11226 next = editor->buffer()->next_char(next);
11230 std::memset((
void*) &buf[p72],
'B', p78 - p72);
11234 std::memset((
void*) &buf[p78],
'C', len - p78);
11237 style->replace(start, start + (
int) len, buf);
11239 start = editor->buffer()->skip_lines(start, 1);
11240 std::free((
void*) buf);
11244 editor->redisplay_range(pos, end);
11251 void ComposeWindow::cancel_cb_i(Fl_Widget* w)
11254 if(Fl::event() == FL_SHORTCUT && Fl::event_key() == FL_Escape)
11259 mainWindow->composeWindow = NULL;
11260 Fl::delete_widget(w);
11262 mainWindow->composeComplete();
11271 void ComposeWindow::send_cb_i(
void)
11281 const char* newsgroups;
11283 const char* organization;
11285 const char* cancel_lock1;
11286 const char* cancel_lock;
11288 const char* injection_date;
11289 const char* header;
11291 const char* expires;
11292 bool free_subject =
false;
11295 bool fup2_present =
false;
11298 newsgroups = newsgroupsField->value();
11299 len = std::strlen(newsgroups);
11302 SC(
"Do not use non-ASCII for the translation of this item")
11303 fl_message_title(S("Error"));
11304 fl_alert("%s", S("Newsgroups list is empty"));
11311 for(i = 0; i < len; ++i)
11313 if(
',' == q[i] ||
'.' == q[i]
11314 ||
'+' == q[i] ||
'-' == q[i] ||
'_' == q[i])
11318 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11319 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11320 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11324 if(
',' == q[0] ||
',' == q[len - (std::size_t) 1]) { rv = -1; }
11325 if(
'.' == q[0] ||
'.' == q[len - (std::size_t) 1]) { rv = -1; }
11328 SC(
"Do not use non-ASCII for the translation of this item")
11329 fl_message_title(S("Error"));
11330 fl_alert("%s", S("Invalid content in Newsgroups header field"));
11334 rv = replaceHeaderField(
"Newsgroups", newsgroups);
11337 SC(
"Do not use non-ASCII for the translation of this item")
11338 fl_message_title(S("Error"));
11339 fl_alert("%s", S("Replacement of Newsgroups in header failed"));
11348 subject = subjectField->value();
11351 SC(
"Do not use non-ASCII for the translation of this item")
11352 fl_message_title(S("Error"));
11353 fl_alert("%s", S("Subject is empty"));
11361 if(!rv) { free_subject =
true; }
11363 rv = replaceHeaderField(
"Subject",
subject);
11366 SC(
"Do not use non-ASCII for the translation of this item")
11367 fl_message_title(S("Error"));
11368 fl_alert("%s", S("Replacement of Subject in header failed"));
11379 organization = extractHeaderField(
"Organization");
11380 if(NULL != organization)
11387 std::strlen(
"Organization: "));
11388 if(0 < rv) { rv = 0; }
11391 rv = replaceHeaderField(
"Organization", q);
11395 std::free((
void*) organization);
11398 SC(
"Do not use non-ASCII for the translation of this item")
11399 fl_message_title(S("Error"));
11400 fl_alert("%s", S("Encoding of Organization header field failed"));
11409 rv = searchHeaderField(
"MIME-Version", &start, &end);
11412 SC(
"Do not use non-ASCII for the translation of this item")
11413 fl_message_title(S("Error"));
11414 fl_alert("%s", S("Bug: Mandatory MIME declaration not found"));
11420 if(!archiveButton->value())
11422 if(replaceHeaderField(
"Archive",
"no"))
11424 compHeader->insert(start,
"Archive: no\n");
11427 else { deleteHeaderField(
"Archive"); }
11429 q = distriField->value();
11432 len = std::strlen(q);
11436 for(i = 0; i < len; ++i)
11438 if(
',' == q[i] ||
'+' == q[i] ||
'-' == q[i] ||
'_' == q[i])
11442 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11443 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11444 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11448 if(
',' == q[0] ||
',' == q[len - (std::size_t) 1]) { rv = -1; }
11452 p = (
char*) std::malloc(len + (std::size_t) 1);
11453 if(NULL == p) { rv = -1; }
11457 for(i = 0; i < len; ++i)
11461 #if defined(__cplusplus) && __cplusplus >= 199711L
11462 p[i] = (char) std::tolower((
int) (
unsigned char) q[i]);
11463 #else // defined(__cplusplus) && __cplusplus >= 199711L
11465 p[i] = (char) tolower((
int) (
unsigned char) q[i]);
11466 #endif // defined(__cplusplus) && __cplusplus >= 199711L
11472 if(NULL != std::strstr(p,
"all")) { rv = -1; }
11477 SC(
"Do not use non-ASCII for the translation of this item")
11478 fl_message_title(S("Error"));
11480 S("Invalid content in Distribution header field"));
11484 else if(NULL == std::strstr(p, "world"))
11486 if(replaceHeaderField(
"Distribution", p))
11488 compHeader->insert(start,
"\n");
11489 compHeader->insert(start, p);
11490 compHeader->insert(start,
"Distribution: ");
11493 else { deleteHeaderField(
"Distribution"); }
11494 std::free((
void*) p);
11497 else { deleteHeaderField(
"Distribution"); }
11501 expires = expireField->value();
11502 if(NULL != expires)
11504 if(std::strlen(expires))
11508 SC(
"Do not use non-ASCII for the translation of this item")
11509 fl_message_title(S("Error"));
11510 fl_alert("%s", S("Invalid
date for Expires header field"));
11515 if(replaceHeaderField(
"Expires", q))
11517 compHeader->insert(start,
"\n");
11518 compHeader->insert(start, q);
11519 compHeader->insert(start,
"Expires: ");
11521 std::free((
void*) q);
11525 else { deleteHeaderField(
"Expires"); }
11530 q = keywordField->value();
11533 len = std::strlen(q);
11537 for(i = 0; i < len; ++i)
11540 if(
',' == q[i] ||
'!' == q[i] ||
'#' == q[i] ||
'$' == q[i]
11541 ||
'%' == q[i] ||
'&' == q[i] ||
'+' == q[i]
11542 ||
'-' == q[i] ||
'/' == q[i] ||
'=' == q[i]
11543 ||
'?' == q[i] ||
'^' == q[i] ||
'_' == q[i]
11544 ||
'{' == q[i] ||
'|' == q[i] ||
'}' == q[i]
11545 ||
'~' == q[i] ||
' ' == q[i])
11549 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11550 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11551 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11557 if(
',' == q[0] ||
',' == q[len]
11558 ||
' ' == q[0] ||
' ' == q[len])
11564 SC(
"Do not use non-ASCII for the translation of this item")
11565 fl_message_title(S("Error"));
11567 S("Invalid content in Keywords header field"));
11571 if(replaceHeaderField(
"Keywords", q))
11573 compHeader->insert(start,
"\n");
11574 compHeader->insert(start, q);
11575 compHeader->insert(start,
"Keywords: ");
11580 else { deleteHeaderField(
"Keywords"); }
11585 q = fup2Field->value();
11588 len = std::strlen(q);
11592 for(i = 0; i < len; ++i)
11594 if(
',' == q[i] ||
'.' == q[i]
11595 ||
'+' == q[i] ||
'-' == q[i] ||
'_' == q[i])
11599 if(0x30 <= q[i] && 0x39 >= q[i]) {
continue; }
11600 if(0x41 <= q[i] && 0x5A >= q[i]) {
continue; }
11601 if(0x61 <= q[i] && 0x7A >= q[i]) {
continue; }
11605 if(
',' == q[0] ||
',' == q[len - (std::size_t) 1])
11609 if(
'.' == q[0] ||
'.' == q[len - (std::size_t) 1])
11615 SC(
"Do not use non-ASCII for the translation of this item")
11616 fl_message_title(S("Error"));
11618 S("Invalid content in Followup-To header field"));
11622 if(replaceHeaderField(
"Followup-To", q))
11624 compHeader->insert(start,
"\n");
11625 compHeader->insert(start, q);
11626 compHeader->insert(start,
"Followup-To: ");
11627 fup2_present =
true;
11632 else { deleteHeaderField(
"Followup-To"); }
11640 msgid = extractHeaderField(
"Message-ID");
11643 std::free((
void*)
msgid);
11644 if(std::strlen(fqdn))
11649 replaceHeaderField(
"Message-ID",
msgid);
11652 rv = searchHeaderField(
"Cancel-Lock", &start, &end);
11656 deleteHeaderField(
"Cancel-Lock");
11660 if(NULL != cancel_lock1 || NULL != cancel_lock)
11662 compHeader->insert(start,
"\n");
11663 if(NULL != cancel_lock)
11665 compHeader->insert(start, cancel_lock);
11666 compHeader->insert(start,
" ");
11668 if(NULL != cancel_lock1)
11670 compHeader->insert(start, cancel_lock1);
11671 compHeader->insert(start,
" ");
11673 compHeader->insert(start,
"Cancel-Lock:");
11687 date = extractHeaderField(
"Date");
11690 std::free((
void*)
date);
11692 rv = replaceHeaderField(
"Date",
date);
11696 SC(
"Do not use non-ASCII for the translation of this item")
11697 fl_message_title(S("Error"));
11698 fl_alert("%s", S("Updating Date header field failed"));
11707 injection_date = extractHeaderField(
"Injection-Date");
11708 if(NULL != injection_date)
11710 std::free((
void*) injection_date);
11712 rv = replaceHeaderField(
"Injection-Date", injection_date);
11716 SC(
"Do not use non-ASCII for the translation of this item")
11717 fl_message_title(S("Error"));
11718 fl_alert("%s", S("Updating Injection-Date header field failed"));
11728 if(std::strchr(newsgroupsField->value(), (int)
',') && !fup2_present)
11730 SC(
"Do not use non-ASCII for the translation of this item")
11731 fl_message_title(S("Warning"));
11732 rv = !fl_choice("%s", S("Cancel"),
11734 S("Xpost without Followup-To\nReally continue?"));
11741 header = compHeader->text();
11742 body = compText->text();
11743 if(NULL == header || NULL == body)
11745 SC(
"Do not use non-ASCII for the translation of this item")
11746 fl_message_title(S("Error"));
11747 fl_alert("%s", S("Out of memory"));
11751 lenh = std::strlen(header);
11752 lenb = std::strlen(body);
11756 SC(
"Do not use non-ASCII for the translation of this item")
11757 fl_message_title(S("Error"));
11758 fl_alert("%s", S("Message body is empty"));
11763 if(checkArticleBody(body))
11765 SC(
"Do not use non-ASCII for the translation of this item")
11766 fl_message_title(S("Error"));
11767 rv = !fl_choice("%s", S("Cancel"),
11769 S("Message body contains no own content"));
11774 p = (
char*) std::malloc(lenh + lenb + (std::size_t) 1);
11777 std::strcpy(p, header);
11778 std::strcat(p, body);
11780 mainWindow->articlePost(UI_CB_START, p);
11784 std::free((
void*) header);
11785 std::free((
void*) body);
11795 void ComposeWindow::uri_insert_cb_i()
11797 const char* scheme = uriSchemeField->value();
11799 const char* body_raw = uriBodyField->value();
11800 const char* body = NULL;
11803 if(std::strlen(scheme))
11805 if(!std::strncmp(scheme,
"http", 4))
11809 else if(!std::strncmp(scheme,
"ftp", 3))
11813 else if(!std::strncmp(scheme,
"news", 4))
11817 else if(!std::strncmp(scheme,
"mailto", 6))
11826 SC(
"Do not use non-ASCII for the translation of this item")
11827 fl_message_title(S("Error"));
11828 fl_alert("%s", S("Creation of URI failed"));
11833 compEditor->insert(
"<");
11835 compEditor->insert(scheme);
11837 compEditor->insert(
":");
11841 compEditor->insert(
"//");
11844 compEditor->insert(body);
11845 uriBodyField->value(
"");
11847 compEditor->insert(
">");
11849 compTabs->value(compGroup);
11850 Fl::focus(compEditor);
11852 if(body != body_raw) {
enc_free((
void*) body); }
11859 ComposeWindow::ComposeWindow(
const char* label,
const char* header,
11861 bool super) : UI_WINDOW_CLASS(795, 395, label)
11863 static const char label_ch[] =
"1-----------------------------------------"
11864 "-------------------------72->|-78->|";
11871 int y, w, h, gy, gh, bw, sh, hh;
11872 int w1, w2, w3, w4, h1, h2, h3;
11873 const char* signature;
11875 const char* newsgroups;
11876 const char**
groups = NULL;
11879 unsigned int signature_warnings = 0;
11880 const char* uri_header;
11881 const char* distribution = NULL;
11882 int dist_msg_flag = 0;
11885 SC(
"Preserve the spaces at beginning and end")
11886 const
char* label_content = S(" Content ");
11887 const
char* label_uri_encoder = S(" URI encoder ");
11888 const
char* label_advanced = S(" Advanced ");
11889 SC("Preserve the colon")
11890 const
char* label_subject = S("Subject:");
11891 const
char* label_change = S("Change");
11892 const
char* label_send = S("Send");
11893 const
char* label_cancel = S("Cancel");
11894 const
char* label_insert = S("Insert");
11898 callback(cancel_cb, (
void*) this);
11901 compHeader = new Fl_Text_Buffer();
11902 compHeader->text(header);
11903 currentStyle = new Fl_Text_Buffer();
11904 compText = new Fl_Text_Buffer();
11905 compText->add_modify_callback(style_update_cb, (
void*) this);
11911 compTabs = new Fl_Tabs(0, 0, 795, 395);
11914 compGroup =
new Fl_Group(0, th - tg, 795, 395 - th + tg, label_content);
11915 compGroup->begin();
11918 gui_set_default_font();
11919 fl_measure(label_send, w1 = 0, h1 = 0);
11920 fl_measure(label_cancel, w2 = 0, h2 = 0);
11921 if(w1 > w2) { w = w1; }
else { w = w2; }
11922 if(h1 > h2) { h = h1; }
else { h = h2; }
11926 gy = 395 - th - gh;
11929 subjectGroup =
new Fl_Group(0, th, 795, sh);
11930 subjectGroup->begin();
11932 gui_set_default_font();
11933 fl_measure(label_subject, w3 = 0, h3 = 0);
11935 fl_measure(label_change, w4 = 0, h3 = 0);
11937 subjectField =
new Fl_Input(w3, th, 795 - w3 - w4, sh,
11939 subjectField->align(FL_ALIGN_LEFT);
11940 subject = extractHeaderField(
"Subject");
11943 subjectField->value(
subject);
11946 p =
new Fl_Button(795 - w4, th, w4, sh, label_change);
11948 S(
"Change subject and cite old one with was: prefix in parenthesis")
11950 p->callback(change_cb, (
void*)
this);
11952 subjectGroup->end();
11953 subjectGroup->resizable(subjectField);
11956 chp =
new Fl_Box(0, th + sh, 795, hh, label_ch);
11957 chp->labelfont(FL_COURIER);
11958 chp->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT);
11960 compEditor =
new Fl_Text_Editor(0, th + sh + hh, 795,
11961 395 - th - sh - hh - gh);
11962 compEditor->textfont(FL_COURIER);
11963 compEditor->show_insert_position();
11964 resizable(compEditor);
11966 styles =
new Fl_Text_Display::Style_Table_Entry[3];
11967 styles[0].color = FL_FOREGROUND_COLOR;
11968 styles[0].font = FL_COURIER;
11969 styles[0].size = compEditor->textsize();
11970 styles[0].attr = 0;
11971 styles[1].color = FL_COLOR_CUBE + (Fl_Color) 35;
11972 styles[1].font = FL_COURIER;
11973 styles[1].size = compEditor->textsize();
11974 styles[1].attr = 0;
11975 styles[2].color = FL_RED;
11976 styles[2].font = FL_COURIER;
11977 styles[2].size = compEditor->textsize();
11978 styles[2].attr = 0;
11979 compEditor->highlight_data(currentStyle, styles, 3,
'A', NULL, NULL);
11981 compEditor->buffer(compText);
11982 if(NULL != article)
11984 compText->insert(0, article);
11988 if (NULL != ca) { gui_cite_content(compText, ca, hdr->
groups); }
11990 gui_check_article(compText);
11992 if(super) { compEditor->insert_position(0); }
11993 else { compEditor->insert_position(compText->length()); }
11996 if(NULL != signature)
12000 if(!super) { compEditor->buffer()->append(
"\n"); }
12003 compEditor->buffer()->append(
"-- \n");
12005 compEditor->buffer()->append(signature);
12010 gp =
new Fl_Group(0, th + gy, 795, gh);
12015 new Fl_Box(0, th + gy, bw, gh);
12016 p =
new Fl_Button(15, y, w, h, label_send);
12017 p->callback(send_cb, (
void*)
this);
12018 new Fl_Box(795 - bw, gy, bw, gh);
12019 p =
new Fl_Button(795 - bw + 15, y, w, h, label_cancel);
12020 p->callback(cancel_cb, (
void*)
this);
12022 bp =
new Fl_Box(bw, th + gy, 795 - (2 * bw), gh);
12028 compGroup->resizable(compEditor);
12032 uriEncGroup =
new Fl_Group(0, th - tg, 795, 395 - th + tg,
12033 label_uri_encoder);
12034 uriEncGroup->begin();
12037 uri_header = S(
"Percent encoder for clickable URIs");
12038 uriHeaderField =
new Fl_Box(5, y, 795 - 10, sh, uri_header);
12039 uriHeaderField->labelfont(FL_HELVETICA_BOLD);
12041 uriSchemeField =
new Fl_Input_Choice(5, y, 795 - 10, sh,
12043 uriSchemeField->tooltip(S(
"Only the selectable schemes are supported"));
12044 uriSchemeField->align(FL_ALIGN_TOP_LEFT);
12045 uriSchemeField->add(
"http");
12046 uriSchemeField->add(
"https");
12047 uriSchemeField->add(
"ftp");
12048 uriSchemeField->add(
"news");
12049 uriSchemeField->add(
"mailto");
12050 uriSchemeField->input()->readonly(1);
12051 uriSchemeField->value(0);
12053 uriBodyField =
new Fl_Input(5, y, 795 - 10, sh, S(
"Body for URI:"));
12054 uriBodyField->align(FL_ALIGN_TOP_LEFT);
12057 fl_measure(label_insert, w1 = 0, h1 = 0);
12060 gp =
new Fl_Group(0, y, 795, h);
12063 p =
new Fl_Button(5, y, w, h, label_insert);
12064 p->callback(uri_insert_cb, (
void*)
this);
12065 fillSpace =
new Fl_Box(5 + w, y, 795 - (10 + w), h);
12068 gp->resizable(fillSpace);
12071 fillSpace =
new Fl_Box(5, y, 795 - 10, 1);
12073 uriEncGroup->end();
12074 uriEncGroup->resizable(fillSpace);
12078 advancedGroup =
new Fl_Group(0, th - tg, 795, 395 - th + tg,
12080 advancedGroup->begin();
12083 newsgroupsField =
new Fl_Input(5, y, 795 - 10, sh,
"Newsgroups:");
12084 newsgroupsField->align(FL_ALIGN_TOP_LEFT);
12085 newsgroupsField->tooltip(S(
"Comma separated list"));
12086 newsgroups = extractHeaderField(
"Newsgroups");
12087 if(NULL != newsgroups)
12089 newsgroupsField->value(newsgroups);
12096 while(NULL !=
groups[i])
12104 std::free((
void*) newsgroups);
12107 fup2Field =
new Fl_Input_Choice(5, y, 795 - 10, sh,
"Followup-To:");
12108 fup2Field->align(FL_ALIGN_TOP_LEFT);
12109 fup2Field->tooltip(S(
"Comma separated list"));
12110 fup2Field->add(
"poster");
12115 if(NULL == hdr->
groups[i]) {
break; }
12119 if(!i && NULL == hdr->
groups[1]) {
break; }
12120 fup2Field->add(hdr->
groups[i]);
12125 if(NULL != hdr->
fup2 && std::strlen(hdr->
fup2))
12127 fup2Field->value(hdr->
fup2);
12132 keywordField =
new Fl_Input_Choice(5, y, 795 - 10, sh,
"Keywords:");
12133 keywordField->align(FL_ALIGN_TOP_LEFT);
12134 keywordField->tooltip(S(
"Comma separated list"));
12135 if(!testGrp) { keywordField->add(
"ignore"); }
12139 std::printf(
"%s: %s"
12140 "Setting keywords from config file for test group\n",
12145 expireField =
new Fl_Input(5, y, 795 - 10, sh,
"Expires:");
12146 expireField->align(FL_ALIGN_TOP_LEFT);
12147 expireField->tooltip(
12148 S(
"Use date in ISO 8601 format YYYY-MM-DD")
12151 distriField =
new Fl_Input_Choice(5, y, 795 - 10, sh,
"Distribution:");
12152 distriField->align(FL_ALIGN_TOP_LEFT);
12153 if(NULL != hdr && NULL != hdr->
dist && std::strlen(hdr->
dist))
12158 std::printf(
"%s: %sFollowing former distribution\n",
12161 distriField->value(hdr->
dist);
12167 newsgroups = extractHeaderField(
"Newsgroups");
12168 if(NULL != newsgroups)
12182 std::free((
void*) newsgroups);
12187 std::printf(
"%s: %sSetting distribution as suggested\n",
12189 distriField->value(distribution);
12192 else { distriField->value(
"world"); }
12194 distriField->add(
"world");
12195 distriField->add(
"local");
12196 distriField->tooltip(
12197 S(
"Use country code or comma separated list of country codes")
12200 archiveButton =
new Fl_Check_Button(5, y, 795 - 10, sh,
"Archive");
12201 archiveButton->set();
12204 fillSpace =
new Fl_Box(5, y, 795 - 10, 1);
12206 advancedGroup->end();
12207 advancedGroup->resizable(fillSpace);
12210 compTabs->resizable(compGroup);
12216 if(!std::strlen(subjectField->value())) { Fl::focus(subjectField); }
12217 else { Fl::focus(compEditor); }
12219 size_range(4 * bw, 395, 0, 0);
12224 SC(
"Do not use non-ASCII for the translation of this item")
12225 fl_message_title(S("Note"));
12226 fl_message("%s", S("Distribution set as suggested by server"));
12232 SC(
"Do not use non-ASCII for the translation of this item")
12233 fl_message_title(S("Error"));
12234 fl_alert("%s", S("Signature has unsupported character set"));
12240 SC(
"Do not use non-ASCII for the translation of this item")
12241 fl_message_title(S("Note"));
12242 fl_message("%s", S("Signature should not be longer than 4
lines"));
12249 #if !CFG_DB_DISABLE
12250 Fl::visual(FL_DOUBLE | FL_INDEX);
12251 #endif // CFG_DB_DISABLE
12258 mainWindow->composeWindowLock = 1;
12259 UI_STATUS(S(
"Waiting for external editor ..."));
12267 ComposeWindow::~ComposeWindow(
void)
12270 compEditor->highlight_data(dummyTb, NULL, 0,
'A', NULL, NULL);
12271 delete currentStyle;
12273 compEditor->buffer(dummyTb);
12299 Fl_Text_Buffer* info;
12300 const char* pass = NULL;
12301 const char* title_psfile;
12307 PRINT_ERROR(
"No thread support available in FLTK");
12314 lockingInitialized =
true;
12317 if(rv) { exitRequest = 1; }
12323 SC(
"This section is for the button labels of popup windows")
12324 fl_cancel = S(
"Cancel");
12325 fl_close = S(
"Close");
12333 SC(
"This section is for the text buffer warning messages")
12334 Fl_Text_Buffer::file_encoding_warning_message
12335 = S(
"Invalid encoding detected, trying to convert data");
12339 SC(
"This section is for the file chooser labels")
12340 Fl_File_Chooser::all_files_label = S(
"*");
12341 Fl_File_Chooser::custom_filter_label = S(
"Custom filter");
12342 Fl_File_Chooser::existing_file_label
12343 = S(
"Please choose an existing file!");
12344 Fl_File_Chooser::favorites_label = S(
"Favorites");
12345 Fl_File_Chooser::add_favorites_label = S(
"Add to favorites");
12346 Fl_File_Chooser::manage_favorites_label = S(
"Manage favorites");
12347 Fl_File_Chooser::filesystems_label = S(
"File systems");
12348 Fl_File_Chooser::new_directory_label = S(
"New directory?");
12349 Fl_File_Chooser::new_directory_tooltip = S(
"Create a new directory.");
12350 Fl_File_Chooser::preview_label = S(
"Preview");
12351 Fl_File_Chooser::hidden_label = S(
"Show hidden files");
12352 Fl_File_Chooser::filename_label = S(
"Filename:");
12353 Fl_File_Chooser::save_label = S(
"Save");
12354 SC(
"The translation for this should not be much longer!")
12355 Fl_File_Chooser::show_label = S(
"Show:");
12360 SC(
"This section is for the print dialog labels")
12361 SC(
"Do not use characters for the translation that cannot be")
12362 SC(
"converted to the ISO 8859-1 character set for this item.")
12363 SC(
"Leave the original string in place if in doubt.")
12364 Fl_Printer::dialog_title = S(
"Print");
12365 Fl_Printer::dialog_printer = S(
"Printer");
12366 Fl_Printer::dialog_range = S(
"Print range");
12367 Fl_Printer::dialog_copies = S(
"Copies");
12368 Fl_Printer::dialog_all = S(
"All");
12369 Fl_Printer::dialog_pages = S(
"Pages");
12370 Fl_Printer::dialog_from = S(
"From:");
12371 Fl_Printer::dialog_to = S(
"To:");
12372 Fl_Printer::dialog_properties = S(
"Properties ...");
12373 Fl_Printer::dialog_copyNo = S(
"Copies:");
12374 Fl_Printer::dialog_print_button = S(
"Print");
12375 Fl_Printer::dialog_cancel_button = S(
"Cancel");
12376 Fl_Printer::dialog_print_to_file = S(
"Print to file");
12381 SC(
"This section is for the printer property dialog labels")
12382 SC(
"Do not use characters for the translation that cannot be")
12383 SC(
"converted to the ISO 8859-1 character set for this item.")
12384 SC(
"Leave the original string in place if in doubt.")
12385 Fl_Printer::property_title = S(
"Printer properties");
12386 Fl_Printer::property_pagesize = S(
"Page size:");
12387 Fl_Printer::property_mode = S(
"Output mode:");
12388 Fl_Printer::property_use = S(
"Use");
12389 Fl_Printer::property_save = S(
"Save");
12390 Fl_Printer::property_cancel = S(
"Cancel");
12395 SC(
"This section is for the print to file chooser dialog label")
12396 SC(
"Do not use characters for the translation that cannot be")
12397 SC(
"converted to the ISO 8859-1 character set for this item.")
12398 SC(
"Leave the original string in place if in doubt.")
12399 title_psfile = S(
"Select a .ps file");
12402 Fl_PostScript_File_Device::file_chooser_title = title_psfile;
12414 #if CFG_CMPR_DISABLE
12417 #endif // CFG_CMPR_DISABLE
12420 dummyTb =
new Fl_Text_Buffer(0, 0);
12421 mainWindow =
new MainWindow(CFG_NAME);
12424 mainWindow->size_range(w, h, 0, 0);
12429 mainWindow->resize(x, y, w, h);
12433 mainWindow->setTilingX(tx);
12434 mainWindow->setTilingY(ty);
12435 mainWindow->redraw();
12438 fl_message_hotspot(0);
12440 #if USE_WINDOW_ICON
12442 mainWindow->default_icon(&mainIcon);
12443 #endif // USE_WINDOW_ICON
12448 #if !CFG_DB_DISABLE
12449 Fl::visual(FL_DOUBLE | FL_INDEX);
12450 #endif // CFG_DB_DISABLE
12451 mainWindow->show(argc, argv);
12456 gui_set_default_font();
12459 info =
new Fl_Text_Buffer;
12460 text = gui_greeting();
12463 mainWindow->articleUpdate(info);
12467 text = S(
"Possible security vulnerability in TLS module detected!");
12469 # if !CFG_TLS_WARNING_DISABLE
12471 # else // !CFG_TLS_WARNING_DISABLE
12473 # endif // !CFG_TLS_WARNING_DISABLE
12476 SC(
"Do not use non-ASCII for the translation of this item")
12477 fl_message_title(S(
"Warning"));
12478 fl_alert(
"%s", text);
12480 #endif // CFG_USE_TLS
12488 SC(
"Do not use non-ASCII for the translation of this item")
12489 fl_message_title(S(
"Note"));
12490 rv = fl_choice(
"%s", S(
"Skip"),
12492 S(
"TLS certificate revocation list \x28\x43RL\x29\nupdate interval elapsed. Update now?"));
12496 std::printf(
"%s: %sTLS certificate CRL updates suppressed\n",
12501 #endif // CFG_USE_TLS
12510 if(NULL == pass) { exitRequest = 1;
break; }
12516 SC(
"Do not use non-ASCII for the translation of this item")
12517 fl_message_title(S(
"Warning"));
12518 fl_alert(
"%s", S(
"Empty password is not supported"));
12525 MainWindow::group_list_refresh_timer_cb((
void*) mainWindow);
12539 offset_correction_x = x - mainWindow->x();
12540 if(20 < offset_correction_x) { offset_correction_x = 0; }
12541 offset_correction_y = y - mainWindow->y();
12542 if(20 < offset_correction_y) { offset_correction_y = 0; }
12559 static const char* tmpfile = NULL;
12560 static long int editor_pid;
12561 static bool editor_term_lock =
false;
12567 if(NULL == mainWindow) { res = 1; }
12571 if(NULL != protocolConsole) { protocolConsole->update(); }
12577 if(NULL == mainWindow->composeWindow)
12579 mainWindow->composeWindowLock = 0;
12581 switch(mainWindow->composeWindowLock)
12586 if(exitRequest) { res = 1; }
12593 if(NULL != tmpfile)
12595 rv = gui_save_to_file(tmpfile, mainWindow->composeWindow
12596 ->compEditor->buffer());
12600 if(!rv) { error =
false; }
12610 UI_STATUS(S(
"Starting external editor failed."));
12611 mainWindow->composeWindowLock = 3;
12613 else { mainWindow->composeWindowLock = 2; }
12622 if(exitRequest && !editor_term_lock)
12626 editor_term_lock =
true;
12632 if(rv) {
UI_STATUS(S(
"External editor reported error.")); }
12636 UI_STATUS(S(
"External editor reported success."));
12637 rv = mainWindow->composeWindow
12638 ->compEditor->buffer()->loadfile(tmpfile);
12641 mainWindow->composeWindow
12642 ->compEditor->buffer()
12643 ->append(S(
"[Importing data from editor failed]"));
12648 mainWindow->composeWindowLock = 3;
12654 editor_term_lock =
false;
12655 mainWindow->composeWindow->show();
12656 mainWindow->composeWindowLock = 0;
12661 PRINT_ERROR(
"Error in external editor state machine (bug)");
12679 if(NULL != mainWindow)
12692 printf(
"%s: %sExport group states for shutdown\n",
12695 mainWindow->groupStateExport();
12701 lockingInitialized =
false;
12705 if(NULL != mainWindow)
12737 return(fl_utf8locale());
12753 case UI_CB_COOKIE_SERVER:
12755 rv = Fl::awake(MainWindow::serverconf_cb, (
void*) mainWindow);
12758 case UI_CB_COOKIE_GROUPLIST:
12760 rv = Fl::awake(MainWindow::subscribe_cb1, (
void*) mainWindow);
12763 case UI_CB_COOKIE_GROUPLABELS:
12765 rv = Fl::awake(MainWindow::subscribe_cb2, (
void*) mainWindow);
12768 case UI_CB_COOKIE_GROUPPROPOSAL:
12770 rv = Fl::awake(MainWindow::groupproposal_cb, (
void*) mainWindow);
12773 case UI_CB_COOKIE_GROUPINFO1:
12775 rv = Fl::awake(MainWindow::refresh_cb1, (
void*) mainWindow);
12778 case UI_CB_COOKIE_GROUPINFO2:
12780 rv = Fl::awake(MainWindow::refresh_cb2, (
void*) mainWindow);
12783 case UI_CB_COOKIE_GROUP:
12785 rv = Fl::awake(MainWindow::group_cb, (
void*) mainWindow);
12788 case UI_CB_COOKIE_OVERVIEW:
12790 rv = Fl::awake(MainWindow::overview_cb, (
void*) mainWindow);
12793 case UI_CB_COOKIE_HEADER:
12795 rv = Fl::awake(MainWindow::header_cb, (
void*) mainWindow);
12798 case UI_CB_COOKIE_BODY:
12800 rv = Fl::awake(MainWindow::body_cb, (
void*) mainWindow);
12803 case UI_CB_COOKIE_MOTD:
12805 rv = Fl::awake(MainWindow::motd_cb, (
void*) mainWindow);
12808 case UI_CB_COOKIE_ARTICLE:
12810 rv = Fl::awake(MainWindow::article_cb, (
void*) mainWindow);
12813 case UI_CB_COOKIE_SRC:
12815 rv = Fl::awake(MainWindow::src_cb, (
void*) mainWindow);
12818 case UI_CB_COOKIE_POST:
12820 rv = Fl::awake(MainWindow::post_cb, (
void*) mainWindow);
12825 PRINT_ERROR(
"Can't assign cookie to callback function");
12832 PRINT_ERROR(
"Registering awake callback failed (fatal error)");
12861 if(lockingInitialized)
12864 if(res) { res = -1; }
12881 if(lockingInitialized)