xref: /haiku/src/kits/mail/ProtocolConfigView.cpp (revision f73f5d4c42a01ece688cbb57b5d332cc0f68b2c6)
1 /*
2  * Copyright 20011, Haiku Inc. All Rights Reserved.
3  * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 //! The standard config view for all protocols.
9 
10 
11 #include "ProtocolConfigView.h"
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 
16 #include <Catalog.h>
17 #include <CheckBox.h>
18 #include <MenuField.h>
19 #include <MenuItem.h>
20 #include <Message.h>
21 #include <PopUpMenu.h>
22 #include <String.h>
23 #include <TextControl.h>
24 
25 #include <crypt.h>
26 
27 
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "ProtocolConfigView"
30 
31 
32 const char* kPartialDownloadLimit = "partial_download_limit";
33 
34 
35 BodyDownloadConfig::BodyDownloadConfig()
36 	:
37 	BView(BRect(0,0,50,50), "body_config", B_FOLLOW_ALL_SIDES, 0)
38 {
39 	const char *partial_text = B_TRANSLATE(
40 		"Partially download messages larger than");
41 
42 	BRect r(0, 0, 280, 15);
43 	fPartialBox = new BCheckBox(r, "size_if", partial_text,
44 		new BMessage('SIZF'));
45 	fPartialBox->ResizeToPreferred();
46 
47 	r = fPartialBox->Frame();
48 	r.OffsetBy(17,r.Height() + 1);
49 	r.right = r.left + be_plain_font->StringWidth("0000") + 10;
50 	fSizeBox = new BTextControl(r, "size", "", "", NULL);
51 
52 	r.OffsetBy(r.Width() + 5,0);
53 	fBytesLabel = new BStringView(r, "kb", B_TRANSLATE("KiB"));
54 	AddChild(fBytesLabel);
55 	fSizeBox->SetDivider(0);
56 
57 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
58 	AddChild(fPartialBox);
59 	AddChild(fSizeBox);
60 	ResizeToPreferred();
61 }
62 
63 
64 void
65 BodyDownloadConfig::SetTo(MailAddonSettings& addonSettings)
66 {
67 	const BMessage* settings = &addonSettings.Settings();
68 
69 	int32 limit = 0;
70 	if (settings->HasInt32(kPartialDownloadLimit))
71 		limit = settings->FindInt32(kPartialDownloadLimit);
72 	if (limit < 0) {
73 		fPartialBox->SetValue(B_CONTROL_OFF);
74 		fSizeBox->SetText("0");
75 		fSizeBox->SetEnabled(false);
76 	} else {
77 		limit = int32(limit / 1024);
78 		BString kb;
79 		kb << limit;
80 		fSizeBox->SetText(kb);
81 		fPartialBox->SetValue(B_CONTROL_ON);
82 		fSizeBox->SetEnabled(true);
83 	}
84 }
85 
86 
87 void
88 BodyDownloadConfig::MessageReceived(BMessage *msg)
89 {
90 	if (msg->what != 'SIZF')
91 		return BView::MessageReceived(msg);
92 	fSizeBox->SetEnabled(fPartialBox->Value());
93 }
94 
95 
96 void
97 BodyDownloadConfig::AttachedToWindow()
98 {
99 	fPartialBox->SetTarget(this);
100 	fPartialBox->ResizeToPreferred();
101 }
102 
103 
104 void
105 BodyDownloadConfig::GetPreferredSize(float *width, float *height)
106 {
107 	*height = fSizeBox->Frame().bottom + 5;
108 	*width = 200;
109 }
110 
111 
112 status_t
113 BodyDownloadConfig::Archive(BMessage* into, bool) const
114 {
115 	into->RemoveName(kPartialDownloadLimit);
116 	if (fPartialBox->Value() == B_CONTROL_ON)
117 		into->AddInt32(kPartialDownloadLimit, atoi(fSizeBox->Text()) * 1024);
118 	else
119 		into->AddInt32(kPartialDownloadLimit, -1);
120 
121 	return B_OK;
122 }
123 
124 
125 namespace {
126 
127 //--------------------Support functions and #defines---------------
128 #define enable_control(name) if (FindView(name) != NULL) ((BControl *)(FindView(name)))->SetEnabled(true)
129 #define disable_control(name) if (FindView(name) != NULL) ((BControl *)(FindView(name)))->SetEnabled(false)
130 
131 BTextControl *AddTextField (BRect &rect, const char *name, const char *label);
132 BMenuField *AddMenuField (BRect &rect, const char *name, const char *label);
133 float FindWidestLabel(BView *view);
134 
135 static float sItemHeight;
136 
137 inline const char *
138 TextControl(BView *parent,const char *name)
139 {
140 	BTextControl *control = (BTextControl *)(parent->FindView(name));
141 	if (control != NULL)
142 		return control->Text();
143 
144 	return "";
145 }
146 
147 
148 BTextControl *
149 AddTextField(BRect &rect, const char *name, const char *label)
150 {
151 	BTextControl *text_control = new BTextControl(rect,name,label,"",NULL,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
152 //	text_control->SetDivider(be_plain_font->StringWidth(label));
153 	rect.OffsetBy(0,sItemHeight);
154 	return text_control;
155 }
156 
157 
158 BMenuField *AddMenuField (BRect &rect, const char *name, const char *label) {
159 	BPopUpMenu *menu = new BPopUpMenu("Select");
160 	BMenuField *control = new BMenuField(rect,name,label,menu,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
161 	control->SetDivider(be_plain_font->StringWidth(label) + 6);
162 	rect.OffsetBy(0,sItemHeight);
163 	return control;
164 }
165 
166 
167 inline BCheckBox *
168 AddCheckBox(BRect &rect, const char *name, const char *label, BMessage *msg = NULL)
169 {
170 	BCheckBox *control = new BCheckBox(rect,name,label,msg);
171 	rect.OffsetBy(0,sItemHeight);
172 	return control;
173 }
174 
175 
176 inline void
177 SetTextControl(BView *parent, const char *name, const char *text)
178 {
179 	BTextControl *control = (BTextControl *)(parent->FindView(name));
180 	if (control != NULL)
181 		control->SetText(text);
182 }
183 
184 
185 float
186 FindWidestLabel(BView *view)
187 {
188 	float width = 0;
189 	for (int32 i = view->CountChildren();i-- > 0;) {
190 		if (BControl *control = dynamic_cast<BControl *>(view->ChildAt(i))) {
191 			float labelWidth = control->StringWidth(control->Label());
192 			if (labelWidth > width)
193 				width = labelWidth;
194 		}
195 	}
196 	return width;
197 }
198 
199 } // unnamed namspace
200 
201 
202 //----------------Real code----------------------
203 BMailProtocolConfigView::BMailProtocolConfigView(uint32 options_mask)
204 	:
205 	BView (BRect(0,0,100,20), "protocol_config_view", B_FOLLOW_LEFT
206 		| B_FOLLOW_TOP, B_WILL_DRAW),
207 	fBodyDownloadConfig(NULL)
208 {
209 	BRect rect(5,5,245,25);
210 	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
211 
212 	// determine font height
213 	font_height fontHeight;
214 	GetFontHeight(&fontHeight);
215 	sItemHeight = (int32)(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 13;
216 	rect.bottom = rect.top - 2 + sItemHeight;
217 
218 	if (options_mask & B_MAIL_PROTOCOL_HAS_HOSTNAME)
219 		AddChild(AddTextField(rect, "host", B_TRANSLATE("Mail server:")));
220 
221 	if (options_mask & B_MAIL_PROTOCOL_HAS_USERNAME)
222 		AddChild(AddTextField(rect, "user", B_TRANSLATE("Username:")));
223 
224 	if (options_mask & B_MAIL_PROTOCOL_HAS_PASSWORD) {
225 		BTextControl *control = AddTextField(rect, "pass",
226 			B_TRANSLATE("Password:"));
227 		control->TextView()->HideTyping(true);
228 		AddChild(control);
229 	}
230 
231 	if (options_mask & B_MAIL_PROTOCOL_HAS_FLAVORS)
232 		AddChild(AddMenuField(rect, "flavor", B_TRANSLATE("Connection type:")));
233 
234 	if (options_mask & B_MAIL_PROTOCOL_HAS_AUTH_METHODS)
235 		AddChild(AddMenuField(rect, "auth_method", B_TRANSLATE("Login type:")));
236 
237 	// set divider
238 	float width = FindWidestLabel(this);
239 	for (int32 i = CountChildren();i-- > 0;) {
240 		if (BTextControl *text = dynamic_cast<BTextControl *>(ChildAt(i)))
241 			text->SetDivider(width + 6);
242 	}
243 
244 	if (options_mask & B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER) {
245 		AddChild(AddCheckBox(rect, "leave_mail_on_server",
246 			B_TRANSLATE("Leave mail on server"), new BMessage('lmos')));
247 		BCheckBox* box = AddCheckBox(rect, "delete_remote_when_local",
248 			B_TRANSLATE("Remove mail from server when deleted"));
249 		box->SetEnabled(false);
250 		AddChild(box);
251 	}
252 
253 	if (options_mask & B_MAIL_PROTOCOL_PARTIAL_DOWNLOAD) {
254 		fBodyDownloadConfig = new BodyDownloadConfig();
255 		fBodyDownloadConfig->MoveBy(0, rect.bottom + 5);
256 		AddChild(fBodyDownloadConfig);
257 	}
258 
259 	// resize views
260 	float height;
261 	GetPreferredSize(&width,&height);
262 	ResizeTo(width,height);
263 	for (int32 i = CountChildren();i-- > 0;) {
264 		// this doesn't work with BTextControl, does anyone know why? -- axeld.
265 		if (BView *view = ChildAt(i))
266 			view->ResizeTo(width - 10,view->Bounds().Height());
267 	}
268 }
269 
270 
271 BMailProtocolConfigView::~BMailProtocolConfigView()
272 {
273 }
274 
275 
276 void
277 BMailProtocolConfigView::SetTo(MailAddonSettings& settings)
278 {
279  	const BMessage* archive = &settings.Settings();
280 
281 	BString host = archive->FindString("server");
282 	if (archive->HasInt32("port"))
283 		host << ':' << archive->FindInt32("port");
284 
285 	SetTextControl(this,"host", host.String());
286 	SetTextControl(this,"user", archive->FindString("username"));
287 
288 	char *password = get_passwd(archive, "cpasswd");
289 	if (password) {
290 		SetTextControl(this,"pass", password);
291 		delete[] password;
292 	} else
293 		SetTextControl(this,"pass", archive->FindString("password"));
294 
295 	if (archive->HasInt32("flavor")) {
296 		BMenuField *menu = (BMenuField *)(FindView("flavor"));
297 		if (menu != NULL) {
298 			if (BMenuItem *item = menu->Menu()->ItemAt(archive->FindInt32("flavor")))
299 				item->SetMarked(true);
300 		}
301 	}
302 
303 	if (archive->HasInt32("auth_method")) {
304 		BMenuField *menu = (BMenuField *)(FindView("auth_method"));
305 		if (menu != NULL) {
306 			if (BMenuItem *item = menu->Menu()->ItemAt(archive->FindInt32("auth_method"))) {
307 				item->SetMarked(true);
308 				if (item->Command() != 'none') {
309 					enable_control("user");
310 					enable_control("pass");
311 				}
312 			}
313 		}
314 	}
315 
316 
317 	BCheckBox *box = (BCheckBox *)(FindView("leave_mail_on_server"));
318 	if (box != NULL)
319 		box->SetValue(archive->FindBool("leave_mail_on_server") ? B_CONTROL_ON : B_CONTROL_OFF);
320 
321 	box = (BCheckBox *)(FindView("delete_remote_when_local"));
322 	if (box != NULL) {
323 		box->SetValue(archive->FindBool("delete_remote_when_local") ? B_CONTROL_ON : B_CONTROL_OFF);
324 
325 		if (archive->FindBool("leave_mail_on_server"))
326 			box->SetEnabled(true);
327 		else
328 			box->SetEnabled(false);
329 	}
330 
331 	if (fBodyDownloadConfig)
332 		fBodyDownloadConfig->SetTo(settings);
333 }
334 
335 
336 void
337 BMailProtocolConfigView::AddFlavor(const char *label)
338 {
339 	BMenuField *menu = (BMenuField *)(FindView("flavor"));
340 	if (menu != NULL) {
341 		menu->Menu()->AddItem(new BMenuItem(label,NULL));
342 		if (menu->Menu()->FindMarked() == NULL)
343 			menu->Menu()->ItemAt(0)->SetMarked(true);
344 	}
345 }
346 
347 
348 void
349 BMailProtocolConfigView::AddAuthMethod(const char *label,bool needUserPassword)
350 {
351 	BMenuField *menu = (BMenuField *)(FindView("auth_method"));
352 	if (menu != NULL) {
353 		BMenuItem *item = new BMenuItem(label,new BMessage(needUserPassword ? 'some' : 'none'));
354 
355 		menu->Menu()->AddItem(item);
356 
357 		if (menu->Menu()->FindMarked() == NULL) {
358 			menu->Menu()->ItemAt(0)->SetMarked(true);
359 			MessageReceived(menu->Menu()->ItemAt(0)->Message());
360 		}
361 	}
362 }
363 
364 
365 void
366 BMailProtocolConfigView::AttachedToWindow()
367 {
368 	BMenuField *menu = (BMenuField *)(FindView("auth_method"));
369 	if (menu != NULL)
370 		menu->Menu()->SetTargetForItems(this);
371 
372 	BCheckBox *box = (BCheckBox *)(FindView("leave_mail_on_server"));
373 	if (box != NULL)
374 		box->SetTarget(this);
375 }
376 
377 
378 void
379 BMailProtocolConfigView::MessageReceived(BMessage *msg)
380 {
381 	switch (msg->what) {
382 		case 'some':
383 			enable_control("user");
384 			enable_control("pass");
385 			break;
386 		case 'none':
387 			disable_control("user");
388 			disable_control("pass");
389 			break;
390 
391 		case 'lmos':
392 			if (msg->FindInt32("be:value") == 1) {
393 				enable_control("delete_remote_when_local");
394 			} else {
395 				disable_control("delete_remote_when_local");
396 			}
397 			break;
398 	}
399 }
400 
401 
402 status_t
403 BMailProtocolConfigView::Archive(BMessage *into, bool deep) const
404 {
405 	const char *host = TextControl((BView *)this,"host");
406 	int32 port = -1;
407 	BString host_name = host;
408 	if (host_name.FindFirst(':') > -1) {
409 		port = atol(host_name.String() + host_name.FindFirst(':') + 1);
410 		host_name.Truncate(host_name.FindFirst(':'));
411 	}
412 
413 	if (into->ReplaceString("server",host_name.String()) != B_OK)
414 		into->AddString("server",host_name.String());
415 
416 	// since there is no need for the port option, remove it here
417 	into->RemoveName("port");
418 	if (port != -1)
419 		into->AddInt32("port",port);
420 
421 	if (into->ReplaceString("username",TextControl((BView *)this,"user")) != B_OK)
422 		into->AddString("username",TextControl((BView *)this,"user"));
423 
424 	// remove old unencrypted passwords
425 	into->RemoveName("password");
426 
427 	set_passwd(into,"cpasswd",TextControl((BView *)this,"pass"));
428 
429 	BMenuField *field;
430 	int32 index = -1;
431 
432 	if ((field = (BMenuField *)(FindView("flavor"))) != NULL) {
433 		BMenuItem *item = field->Menu()->FindMarked();
434 		if (item != NULL)
435 			index = field->Menu()->IndexOf(item);
436 	}
437 
438 	if (into->ReplaceInt32("flavor",index) != B_OK)
439 		into->AddInt32("flavor",index);
440 
441 	index = -1;
442 
443 	if ((field = (BMenuField *)(FindView("auth_method"))) != NULL) {
444 		BMenuItem *item = field->Menu()->FindMarked();
445 		if (item != NULL)
446 			index = field->Menu()->IndexOf(item);
447 	}
448 
449 	if (into->ReplaceInt32("auth_method",index) != B_OK)
450 		into->AddInt32("auth_method",index);
451 
452 	if (FindView("leave_mail_on_server") != NULL) {
453 		BControl* control = (BControl*)FindView("leave_mail_on_server");
454 		bool on = (control->Value() == B_CONTROL_ON);
455 		if (into->ReplaceBool("leave_mail_on_server", on) != B_OK)
456 			into->AddBool("leave_mail_on_server", on);
457 
458 		control = (BControl*)FindView("delete_remote_when_local");
459 		on = (control->Value() == B_CONTROL_ON);
460 		if (into->ReplaceBool("delete_remote_when_local", on)) {
461 			into->AddBool("delete_remote_when_local", on);
462 		}
463 	} else {
464 		if (into->ReplaceBool("leave_mail_on_server", false) != B_OK)
465 			into->AddBool("leave_mail_on_server", false);
466 
467 		if (into->ReplaceBool("delete_remote_when_local", false) != B_OK)
468 			into->AddBool("delete_remote_when_local", false);
469 	}
470 
471 	if (fBodyDownloadConfig)
472 		fBodyDownloadConfig->Archive(into, deep);
473 	return B_OK;
474 }
475 
476 
477 void
478 BMailProtocolConfigView::GetPreferredSize(float *width, float *height)
479 {
480 	float minWidth = 250;
481 	if (BView *view = FindView("delete_remote_when_local")) {
482 		float ignore;
483 		view->GetPreferredSize(&minWidth,&ignore);
484 	}
485 	if (minWidth < 250)
486 		minWidth = 250;
487 	*width = minWidth + 10;
488 	*height = (CountChildren() * sItemHeight) + 5;
489 
490 	if (fBodyDownloadConfig) {
491 		float bodyW, bodyH;
492 		fBodyDownloadConfig->GetPreferredSize(&bodyW, &bodyH);
493 		*height+= bodyH;
494 	}
495 }
496 
497