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
32const char* kPartialDownloadLimit = "partial_download_limit";
33
34
35BodyDownloadConfig::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", "KB");
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
64void
65BodyDownloadConfig::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
87void
88BodyDownloadConfig::MessageReceived(BMessage *msg)
89{
90	if (msg->what != 'SIZF')
91		return BView::MessageReceived(msg);
92	fSizeBox->SetEnabled(fPartialBox->Value());
93}
94
95
96void
97BodyDownloadConfig::AttachedToWindow()
98{
99	fPartialBox->SetTarget(this);
100	fPartialBox->ResizeToPreferred();
101}
102
103
104void
105BodyDownloadConfig::GetPreferredSize(float *width, float *height)
106{
107	*height = fSizeBox->Frame().bottom + 5;
108	*width = 200;
109}
110
111
112status_t
113BodyDownloadConfig::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
125namespace {
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
131BTextControl *AddTextField (BRect &rect, const char *name, const char *label);
132BMenuField *AddMenuField (BRect &rect, const char *name, const char *label);
133float FindWidestLabel(BView *view);
134
135static float sItemHeight;
136
137inline const char *
138TextControl(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
148BTextControl *
149AddTextField(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
158BMenuField *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
167inline BCheckBox *
168AddCheckBox(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
176inline void
177SetTextControl(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
185float
186FindWidestLabel(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----------------------
203BMailProtocolConfigView::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
271BMailProtocolConfigView::~BMailProtocolConfigView()
272{
273}
274
275
276void
277BMailProtocolConfigView::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
336void
337BMailProtocolConfigView::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
348void
349BMailProtocolConfigView::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
365void
366BMailProtocolConfigView::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
378void
379BMailProtocolConfigView::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
402status_t
403BMailProtocolConfigView::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
477void
478BMailProtocolConfigView::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