1<?php
2	/**************************************************************************\
3	* AngleMail - E-Mail Module for phpGroupWare					*
4	* http://www.anglemail.org									*
5	* http://www.phpgroupware.org									*
6	*/
7	/**************************************************************************\
8	* AngleMail - HTML Widgets									*
9	* This file written by "Angles" Angelo Puglisi <angles@aminvestments.com>	*
10	* Email related HTML Widgets and Utility Functions					*
11	* Copyright (C) 2002 Angelo Tony Puglisi (Angles)					*
12	* -------------------------------------------------------------------------		*
13	* This library is free software; you can redistribute it and/or modify it		*
14	* under the terms of the GNU Lesser General Public License as published by	*
15	* the Free Software Foundation; either version 2.1 of the License,			*
16	* or any later version.											*
17	* This library is distributed in the hope that it will be useful, but			*
18	* WITHOUT ANY WARRANTY; without even the implied warranty of	*
19	* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	*
20	* See the GNU Lesser General Public License for more details.			*
21	* You should have received a copy of the GNU Lesser General Public License	*
22	* along with this library; if not, write to the Free Software Foundation,		*
23	* Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA			*
24	\**************************************************************************/
25
26	/* $Id: class.html_widgets.inc.php 15464 2004-11-06 16:13:49Z powerstat $ */
27	/*!
28	@class html_option
29	@abstract data structure used with class html_widgets
30	@param $value (class var) (string) this options value that will be submitted if selected
31	@param $text (class var) (string) the text the user sees, a description of this option
32	@param $selected  (class var) (boolean)  whether this option should be pre-selected in a combobox, default False
33	@author Angles
34	@discussion used in making select text, value items, such as in the combobox widget.
35	@access private
36	*/
37	class html_option
38	{
39		var $value;
40		var $text;
41		var $selected;
42
43		function html_option()
44		{
45			$this->value = '';
46			$this->text = '';
47			$this->selected = False;
48		}
49	}
50
51	/*!
52	@class hiddenvar_option
53	@abstract data structure used with hidden data in forms
54	@discussion ?
55	@access private
56	*/
57	class hiddenvar_option
58	{
59		var $name;
60		var $value;
61
62		function hiddenvar_option()
63		{
64			$this->name = '';
65			$this->value = '';
66		}
67	}
68
69	/*!
70	@class html_widgets
71	@abstract generate HTML widgets for use in web pages.
72	@author Angles
73	@access public
74	@discussion OOP style class for producing common widgets in html pages, such as a combobox.
75	Designed to reduce bain damage to the developer by hiding the details of the html tags and by
76	treating these things as widgets which is what they are, more than just simple html markup.
77	*/
78	class html_widgets
79	{
80		/**************************************************************************\
81		*	VARS
82		\**************************************************************************/
83		var $debug = 0;
84		var $debug_init = 0;
85
86		// if calling from home page it is optional to force currentapp as a constructor param
87		var $my_currentapp='';
88		// bootstraper for the msg class
89		var $msg_bootstrap;
90		// private template to var names do not collide
91		var $tpl;
92
93		// A HREF OOP properties
94		var $href_link='';
95		var $href_target='';
96		var $href_clickme='not_provided';
97		var $href='';
98
99		// combo box OOP properties
100		var $cbox_name='not_provided';
101		var $cbox_onChange='';
102		var $cbox_items=array();
103		var $combobox='';
104
105		// form OOP properties
106		var $form_name='';
107		var $form_action='';
108		var $form_method='';
109		var $form_hiddenvars=array();
110		var $form='';
111
112		// TOOLBAR
113		var $toolbar_msg='';
114		var $toolbar_row_one='';
115		var $toolbar_row_two='';
116		var $toolbar='';
117
118		// ALL FOLDERS ALL ACCOUNTS MEGA LISTBOX
119		var $F_megalist_form_reference='';
120		var $F_megalist_widget_name='';
121		var $F_megalist_preselected_fldball='';
122		var $F_megalist_skip_fldball='';
123		var $F_megalist_first_item_text = '';
124
125		// RELOAD WIDGET
126		var $refresh_js='';
127
128		// GENERIC ERROR REPORT
129		var $F_mindless_default_txt = 'error text not provided';
130		var $F_error_report_text='';
131		var $F_go_somewhere_link='';
132		var $F_go_home_link='';
133
134
135		/**************************************************************************\
136		*	CONSTRUCTOR
137		\**************************************************************************/
138		function html_widgets()
139		{
140			if ($this->debug_init > 0) { echo 'ENTER: email.html_widgets.CONSTRUCTOR'.'<br />'."\r\n"; }
141			/*!
142			@class requires including spell_struct header file
143			@discussion  class html_widgets needs the special C-Style Include .h like file,
144			class.spell_struct which holds data structure class correction_info used here for integration
145			with the mail.spell  spellchecking class.
146			*/
147			$required_class = 'spell_struct';
148
149			// if calling this class from the home page, then the currentapp will be
150			//set to "home" instead of "email", which messes up the include statement below,
151			// so set a local var to "email" to force considering the currentapp to be "email".
152			$this->my_currentapp = 'email';
153			//require_once(PHPGW_INCLUDE_ROOT.'/'.$GLOBALS['phpgw_info']['flags']['currentapp'].'/inc/class.'.$required_class.'.inc.php');
154			require_once(PHPGW_INCLUDE_ROOT.'/'.$this->my_currentapp.'/inc/class.'.$required_class.'.inc.php');
155
156			if ($this->debug_init > 0) { echo 'EXIT: email.html_widgets.CONSTRUCTOR'.'<br />'."\r\n"; }
157			return;
158		}
159
160
161		/**************************************************************************\
162		*	HREF LINK WIDGET
163		\**************************************************************************/
164
165		/*!
166		@capability HREF LINK WIDGET
167		@discussion generate an a href item, includes link, target, text. CLEARS ITSELF after each "get_href"
168		@author Angles
169		@example $this->widgets->set_href_link('index.php');
170		$this->widgets->set_href_target('top');
171		$this->widgets->get_href_clickme(lang('click here for more info in a new window'));
172		$my_href_tag = $this->widgets->get_href();
173		*/
174		/*!
175		@function clear_href_vars
176		@abstract after every call to "->get_href" all internal vars are cleared automatically with this function.
177		@author Angles
178		@discussion href class vars for link, target, text. CLEARS ITSELF after each "get_href". This utilty
179		function does that. It is RARE that you would ever need to call this directly.
180		@access private
181		*/
182		function clear_href_vars()
183		{
184			$this->set_href_link('');
185			$this->set_href_target('');
186			$this->set_href_clickme('');
187		}
188
189		/*!
190		@function set_href_link
191		@abstract set the URL link of this this HREF widget
192		@param $href_link (string)
193		@author Angles
194		@access public
195		*/
196		function set_href_link($href_link='')
197		{
198			$this->href_link = $href_link;
199		}
200		/*!
201		@function get_href_link
202		@abstract used check or verify the value if the "href_link" property
203		@author Angles
204		@access public
205		*/
206		function get_href_link()
207		{
208			return $this->href_link;
209		}
210
211		/*!
212		@function set_href_target
213		@abstract OPTIONAL set the "target", i.e. what browser window this HREF should apply to,
214		default is not to specify any target in the HREF tag.
215		@param $href_target (string)
216		@author Angles
217		@access public
218		*/
219		function set_href_target($href_target='')
220		{
221			$this->href_target = $href_target;
222		}
223		/*!
224		@function get_href_target
225		@abstract used check or verify the value if the "href_target" property
226		@author Angles
227		@access public
228		*/
229		function get_href_target()
230		{
231			return $this->href_target;
232		}
233
234		/*!
235		@function set_href_clickme
236		@abstract what the user needs to click on to activate the HREF link, can be text or a COMPLETE img tag.
237		@param $href_clickme (string)  text or a COMPLETE img tag
238		@author Angles
239		@access public
240		*/
241		function set_href_clickme($href_clickme='')
242		{
243			$this->href_clickme = $href_clickme;
244		}
245		/*!
246		@function get_href_clickme
247		@abstract used check or verify the value if the "href_clickme" property
248		@author Angles
249		@access public
250		*/
251		function get_href_clickme()
252		{
253			return $this->href_clickme;
254		}
255
256		/*!
257		@function get_href
258		@abstract generate and return an HREF tag using information you set in the OOP "set_href_" functions
259		@author Angles
260		@result (string) a complete HREF tag generated from data you set in the "set_href_" functions,
261		@discussion After you set "href_target", "href_clickme" and other optional properties ("href_target") this
262		function generates an HREF tag from that data and returns it. NOTE after generating the HREF tag, and
263		before returning it, this function CLEARS ALL PROPERTIES that it used to make that href tag, so this
264		"widget" automatically is ready to new usage without having to explicitly call any "new" or "clear" function.
265		@access public
266		*/
267		function get_href()
268		{
269			if ($this->href_target != '')
270			{
271				$target = ' target="'.$this->href_target.'"';
272			}
273			// put the href return value in storage so we can clear all href internal vars before we exit this function with a return.
274			$href = '<a href="' .$this->href_link .'"'.$target.'>' .$this->href_clickme .'</a>' ."\r\n";
275			// this widget clears itself automatically after every call to this function.
276			$this->clear_href_vars();
277			return $href;
278		}
279
280		/**************************************************************************\
281		*	QUICK HREF TAG - depreciated
282		\**************************************************************************/
283		/*!
284		@function href_maketag (not related to the HREF widget)
285		@abstract QUICK way to generate a typical A HREF html item in a single function call. NOT PART OF
286		THE HREF WIDGET, not OOP style, just a quick utilty function. ALL params must be passed in this function call.
287		@param $href_link (string) URL for this HREF tag
288		@param $href_text (string) what the user clicks on to activate this HREF tag, can be text OR a COMPLETE IMG tag.
289		@param $target (string) OPTIONAL target for the link, such as when using frames or opening a new browser window.
290		@author Angles
291		@discussion not really a widget, does not use OOP style, but it gets the job done quickly. Somewhat Depreciated,
292		use the OOP style href widget instead.
293		@example this->href_maketag("index.jsp", "click here for home page", "new");
294		@access public
295		*/
296		function href_maketag($href_link='',$href_text='default text',$target='')
297		{
298			if ($target != '')
299			{
300				$target = ' target="'.$target.'"';
301			}
302			return '<a href="' .$href_link .'"'.$target.'>' .$href_text .'</a>' ."\r\n";
303		}
304
305		/**************************************************************************\
306		*	QUICK IMG TAG
307		\**************************************************************************/
308		/*!
309		@function img_maketag
310		@abstract quick and dirty to make an IMG html tag in one function call.
311		@author Angles
312		@param $location (string int) URL to the image, cal be releative or fully qualified
313		@param $alt (string) text displayed (a) in place of the image if not displayed, and (b) as a image tooltip on some browsers
314		@param $height (string int) int passed as a string, OPTIONAL, not included in img tag if not provided
315		@param $width (string int)  int passed as a string OPTIONAL, not included in img tag if not provided
316		@param $border (string int) int passed as string OPTIONAL , not included in img tag if not provided ,
317		the size of the border around the image, often set to "0"
318		@discussion not really a widget but it gets the job done. QUICK way to generate a typical A IMG html item
319		in a single function call. Not OOP style, just a quick utilty function. ALL params must be passed in this function call.
320		@example $my_img = widgets->img_maketag("poweredby.png", "powered by RedHat",  "", "", "0");
321		@access public
322		*/
323		function img_maketag($location='',$alt='',$height='',$width='',$border='')
324		{
325			$alt_default_txt = 'image';
326			$alt_unknown_txt = 'unknown';
327			if ($location == '')
328			{
329				return '<img src="" alt="['.$alt_unknown_txt.']">';
330			}
331			if ($alt != '')
332			{
333				$alt_tag = ' alt="['.$alt.']"';
334				$title_tag = ' title="'.$alt.'"';
335			}
336			else
337			{
338				$alt_tag = ' alt="['.$alt_default_txt.']"';
339				$title_tag = '';
340			}
341			if ($height != '')
342			{
343				$height_tag = ' height="' .$height .'"';
344			}
345			else
346			{
347				$height_tag = '';
348			}
349			if ($width != '')
350			{
351				$width_tag = ' width="' .$width .'"';
352			}
353			else
354			{
355				$width_tag = '';
356			}
357			if ($border != '')
358			{
359				$border_tag = ' border="' .$border .'"';
360			}
361			else
362			{
363				$border_tag = '';
364			}
365			$image_html = '<img src="'.$location.'"' .$height_tag .$width_tag .$border_tag .$title_tag .$alt_tag .'>';
366			return $image_html;
367		}
368
369		/**************************************************************************\
370		*	COMBOBOX WIDGET
371		\**************************************************************************/
372
373		/*!
374		@capability COMBOBOX WIDGET
375		@discussion generate a combo box html widget.
376		@author Angles
377		@example
378		$this->widgets->new_combobox();
379		$this->widgets->set_cbox_name("user_choice");
380		$this->widgets->set_cbox_item("yes"', "Customer is Right");
381		$this->widgets->set_cbox_item("no"', "Customer is Wrong");
382		$my_combobox_wirget = $this->widgets->get_combobox();
383		*/
384		// combo box OOP access functions
385		/*!
386		@function set_cbox_name
387		@abstract ?
388		*/
389		function set_cbox_name($str='')
390		{
391			if ($str == '')
392			{
393				$this->cbox_name = 'not_provided';
394			}
395			else
396			{
397				$this->cbox_name = $str;
398			}
399		}
400		/*!
401		@function get_cbox_name
402		@abstract ?
403		*/
404		function get_cbox_name()
405		{
406			return $this->cbox_name;
407		}
408
409		/*!
410		@function set_cbox_onChange
411		@abstract ?
412		*/
413		function set_cbox_onChange($str='')
414		{
415			if ($str != '')
416			{
417				$this->cbox_onChange = $str;
418			}
419		}
420		/*!
421		@function get_cbox_onChange
422		@abstract ?
423		*/
424		function get_cbox_onChange()
425		{
426			return $this->cbox_onChange;
427		}
428
429		/*!
430		@function set_cbox_item
431		@abstract ?
432		*/
433		function set_cbox_item($value='',$text='',$selected=False)
434		{
435			// make sure $selected is boolean
436			if (!is_bool($selected))
437			{
438				// replace param with a default boolean value of False
439				$selected = False;
440			}
441			// I've actually seen bomboboxes with an item (usually the first) with no name
442			if (($value != '') || ($text != ''))
443			{
444				$item_idx = count($this->cbox_items);
445				$this->cbox_items[$item_idx] = new html_option;
446				$this->cbox_items[$item_idx]->value = $value;
447				$this->cbox_items[$item_idx]->text = $text;
448				$this->cbox_items[$item_idx]->selected = $selected;
449			}
450		}
451		/*!
452		@function set_cbox_item_spellcheck
453		@abstract makes a special kind of combobox select item for use with spellcheck
454		@param $this_bad_word_element (class "correction_info" structued data from file class.spell_struct)
455		@param $suggestion_num (int OR empty string) see discussion below.
456		@author Angles
457		@discussion  This function makes use of structure "correction_info" which we expose
458		by including file class.spell_struct in the constructor for this class. The combobox select item this
459		function makes embeds array data in the items "value" by setting it to a string that
460		resembles a URL get request, which we then can recover this array by applying php function
461		parse_str to the value when the user submits the form. The idea is to provide enough data
462		in the value that the spellcheck replacement code can accurately find and replace the desired
463		word, or not change the word at all if special suggestion string "K_E_E_P" is present.
464		The first suggestion should be en empty string with special value "K_E_E_P"
465		which means no change to the misspelled word, this is indicated by passing an empty string
466		for param $suggestion_num.
467		The value for the suggestion item is a URL type string that contains as much informaion
468		as we can preserve from the $this_bad_word_element object param, but specifying the individual
469		suggestion provieded by the $suggestion_num arg which is the index to this particular
470		suggestion in the $this_bad_word_element->suggestions[] numbered array of suggestions.
471		Upon submit, we can apply php function parse_str() to this uri to recover the desired array structure.
472		Parse_str will even urldecode the items for us.
473		*/
474		function set_cbox_item_spellcheck($this_bad_word_element='', $suggestion_num='')
475		{
476			// we included the spell_struct file above, so this object knows what
477			// correction_info struct is
478			if (is_object($this_bad_word_element))
479			{
480				if ((string)$suggestion_num != '')
481				{
482					$suggestion_txt = $this_bad_word_element->suggestions[(int)$suggestion_num];
483					$suggestion_value = $this_bad_word_element->suggestions[(int)$suggestion_num];
484				}
485				else
486				{
487					// the first suggestion should be en empty string with special value "K_E_E_P"
488					// which means no change to the misspelled word
489					// this is indicated by passing an empty string for $suggestion_num
490					$suggestion_txt = '';
491					$suggestion_value = 'K_E_E_P';
492				}
493				// the value for the suggestion item is a URL type string that contains as much informaion
494				// as we can preserve from the $this_bad_word_element object, but specifying the individual
495				// suggection provieded by the $suggestion_num arg which is the index to this particular
496				// suggestion in the $this_bad_word_element->suggestions[] numbered array of suggestions
497				// upon submit, we can apply php function parse_str() to this uri to recover the desired array structure.
498				// parse_str will even urldecode the items for us.
499				/*
500				$uri_value =
501					  'cbox[orig_word]='.urlencode($this_bad_word_element->orig_word)
502					.'&cbox[orig_word_clean]='.urlencode($this_bad_word_element->orig_word_clean)
503					.'&cbox[line_num]='.urlencode($this_bad_word_element->line_num)
504					.'&cbox[word_num]='.urlencode($this_bad_word_element->word_num)
505					.'&cbox[suggestion_value]='.urlencode($suggestion_value);
506				*/
507				$uri_value =
508					  'orig_word='.urlencode($this_bad_word_element->orig_word)
509					.'&orig_word_clean='.urlencode($this_bad_word_element->orig_word_clean)
510					.'&line_num='.urlencode($this_bad_word_element->line_num)
511					.'&word_num='.urlencode($this_bad_word_element->word_num)
512					.'&suggestion_value='.urlencode($suggestion_value);
513
514				$item_idx = count($this->cbox_items);
515				$this->cbox_items[$item_idx] = new html_option;
516				$this->cbox_items[$item_idx]->value = $uri_value;
517				$this->cbox_items[$item_idx]->text = $suggestion_txt;
518			}
519		}
520		/*!
521		@function get_cbox_item
522		@abstract ?
523		*/
524		function get_cbox_item($idx='')
525		{
526			if ((string)$idx == '')
527			{
528				return $this->cbox_items;
529			}
530			else
531			{
532				return $this->cbox_items[$idx];
533			}
534		}
535
536		/*!
537		@function new_combobox
538		@abstract ALWAYS start a new combobox widget by calling this function first. Clears all combobox
539		properties.
540		*/
541		function new_combobox()
542		{
543			$this->cbox_name='not_provided';
544			$this->cbox_onChange='';
545			$this->cbox_items=array();
546			$this->combobox='';
547		}
548
549		/*!
550		@function get_combobox
551		@abstract generate and return a HTML select (combobo) widget using the values you set in
552		the "set_cbox_" functions.
553		@author Angles
554		@discussion this function does not clear its properties, so if for some reason you want THE SAME
555		comboboxes more then one time, calling "get_combobox" will return the same combobox until you
556		clear it by calling "new_combobox", which you should ALWAYS do when starting a new combobox
557		widget. VALUES ARE NOT URLENCODED, except that the special spellcheck item stuff
558		does it, but before this function, and this does not happen for the normal set cbox item. It IS
559		html specialchars encoded here.
560		@access public
561		*/
562		function get_combobox()
563		{
564			if ($this->cbox_onChange != '')
565			{
566				$onChange_tag = ' onChange="'.$this->cbox_onChange.'"';
567			}
568			else
569			{
570				$onChange_tag = '';
571			}
572			$this->combobox = '<select name="'.$this->cbox_name.'"'.$onChange_tag.'>';
573			$loops = count($this->cbox_items);
574			if ($loops > 0)
575			{
576				for ($i=0; $i < $loops; $i++)
577				{
578					if ($this->cbox_items[$i]->selected == True)
579					{
580						$selected_tag = ' selected';
581					}
582					else
583					{
584						$selected_tag = '';
585					}
586					$this->combobox .=
587						'<option value="'.$this->cbox_items[$i]->value.'"'.$selected_tag.'>'
588						.htmlspecialchars($this->cbox_items[$i]->text)
589						.'</option>';
590					$this->combobox .= "\r\n";
591				}
592			}
593			$this->combobox .= '</select>';
594			return $this->combobox;
595		}
596		// <select name="filter" onChange="this.form.submit();"><option value="all">show all</option>
597		// <option value="public">only yours</option>
598		// <option value="private">Private</option>
599		// </select>
600
601		/**************************************************************************\
602		*	FORM WIDGET
603		\**************************************************************************/
604
605		/*!
606		@capability FORM WIDGET
607		@discussion generate a opening tag of a form including name, action, method, and hiddenvars
608		@author Angles
609		@example
610		$this->widgets->new_form();
611		$this->widgets->set_form_name('spell_review');
612		$this->widgets->set_form_method('POST');
613		$this->widgets->set_form_action('index.php?email.targets.move');
614		$this->widgets->set_form_hiddenvar('subject', 'stock');
615		$this->widgets->set_form_hiddenvar('symbol', 'GM');
616		// OPTIONAL if you have set "preserve_vars" you can include them as hidden vars with this command
617		$this->commit_preserve_vars_to_form();
618		$my_form_tag = $this->widgets->get_form();
619		*/
620		function new_form()
621		{
622			$this->form_name='not_provided';
623			$this->form_action='';
624			$this->form_method='POST';
625			$this->form_hiddenvars=array();
626			$this->form = '';
627		}
628
629		/*!
630		@function set_form_name
631		@abstract ?
632		*/
633		function set_form_name($str='')
634		{
635			if ($str != '')
636			{
637				$this->form_name = $str;
638			}
639		}
640		/*!
641		@function get_form_name
642		@abstract ?
643		*/
644		function get_form_name()
645		{
646			return $this->form_name;
647		}
648
649		/*!
650		@function set_form_action
651		@abstract ?
652		*/
653		function set_form_action($str='')
654		{
655			if ($str != '')
656			{
657				$this->form_action = $str;
658			}
659		}
660		/*!
661		@function
662		@abstract ? get_form_action
663		*/
664		function get_form_action()
665		{
666			return $this->form_action;
667		}
668
669		/*!
670		@function set_form_method
671		@abstract ?
672		*/
673		function set_form_method($str='')
674		{
675			if ($str != '')
676			{
677				$this->form_method = $str;
678			}
679		}
680		/*!
681		@function get_form_method
682		@abstract ?
683		*/
684		function get_form_method()
685		{
686			return $this->form_method;
687		}
688
689		/*!
690		@function set_form_hiddenvar
691		@abstract put hidden  vars in a form tag.
692		@param $name the "key" in the GPC key - value pair
693		@param $value  the "value" in the GPC key - value pair
694		@param $do_urlencode (boolean) OPTIONAL default is True, whether or not to urlencode the name and value params.
695		@author Angles
696		@access public
697		*/
698		function set_form_hiddenvar($name='',$value='', $do_urlencode=True)
699		{
700			// I've actually seen bomboboxes with an item (usually the first) with no name
701			if (($name != '') || ($value != ''))
702			{
703				if ($do_urlencode == True)
704				{
705					$name = urlencode($name);
706					$value = urlencode($value);
707				}
708				$item_idx = count($this->form_hiddenvars);
709				$this->form_hiddenvars[$item_idx] = new hiddenvar_option;
710				$this->form_hiddenvars[$item_idx]->name = $name;
711				$this->form_hiddenvars[$item_idx]->value = $value;
712			}
713		}
714		/*!
715		@function get_form_hiddenvar
716		@abstract ?
717		*/
718		function get_form_hiddenvar($idx='')
719		{
720			if ((string)$idx == '')
721			{
722				return $this->form_hiddenvars;
723			}
724			else
725			{
726				return $this->form_hiddenvars[$idx];
727			}
728		}
729
730		// <form enctype="multipart/form-data" name="spell_review" action="/mail/index.php?menuaction=email.bosend.sendorspell&fldball[folder]=INBOX&fldball[acctnum]=3&sort=1&order=1&start=0" method="POST">
731		//<input type="hidden" name="sort" value="1">
732		//<input type="hidden" name="order" value="1">
733		//<input type="hidden" name="start" value="0">
734		//<input type="hidden" name="force_showsize" value="1">
735		/*!
736		@function get_form
737		@abstract generate and return an opening FORM tag using the data you set in the "set_form_" functions.
738		@author Angles
739		@discussion Any hiddenvars will be urlencoded. NOTE YOU MUST PUT THE CLOSING &lt;&#047;form&gt; somewhere
740		after this form tag. This functions generates the opening tag of the form, which is where all the complicated stuff
741		is. The ending tag is a normal html markup closing tag you must supply. NOTE on form enctype, HTML 401 says
742		"multipart/form-data" is very strict to MIME rfc2045-49 and will add hard wrap CRLF to each line of text
743		in any control. For example, a TEXTAREA input control will hard wrap at whatever its column length is,
744		because it represents the end of a line of text, eventhough the user did not explicitly press return, and therefor
745		it should be a soft return, not a CRLF. On the other hand, "application/x-www-form-urlencoded" is the default
746		value and is assumed if not provided, and is the kind of submit we are more used to. NOTE "multipart/form-data"
747		is also designed to handle large amounts of text or binary data, so "multipart/form-data" is used with file upload
748		forms, which means "multipart/form-data" WILL NOT WORK if the php.ini file does not allow "FILE UPLOADS".
749		This can be a confusing issue because we are not submitting a file upload, just some text, but the
750		"multipart/form-data"  is used for file upload forms, hence the association.  UPDATE testing shows this
751		may not be true eventhough HTML v401 says so. In a TEXTAREA control, using wrap="hard" yields the
752		CRLF hard wrap regardless of the enctype, and without the wrap="hard" there is no CRLF line ends to soft
753		wraps, eventhough there should be with "multipart/form-data" forms.
754		@access prublic
755		*/
756		function get_form()
757		{
758			$this->form =
759				// '<form enctype="multipart/form-data" '
760				 '<form enctype="application/x-www-form-urlencoded" '
761				.'name="'.$this->form_name.'" '
762				.'action="'.$this->form_action.'" '
763				.'method="'.$this->form_method.'">'
764				."\r\n";
765
766			$loops = count($this->form_hiddenvars);
767			if ($loops > 0)
768			{
769				for ($i=0; $i < $loops; $i++)
770				{
771					$this->form .=
772						 '<input type="hidden" '
773						.'name="'.$this->form_hiddenvars[$i]->name.'" '
774						.'value="'.$this->form_hiddenvars[$i]->value.'">';
775					// just to be safe, send a line break after every one of these
776					$this->form .= "\r\n";
777				}
778			}
779			return $this->form;
780		}
781
782		/*!
783		@function form_closetag
784		@abstract SIMPLE - returns the closing tag for a form &lt;&#047;form&gt;
785		@author Angles
786		@discussion This seems dumb at first, but take the folders combobox as an example,
787		when the user selects a folder from the combbox the OnChange submits the form associated
788		with that combobox, i.e. the form OnChange and the form name should be the same name and
789		the form age should surround the combobox, I think, Anyway, IMAP servers have folders but
790		POP servers do now, so we will not show said folder combobox if viewing a POP3 mail server.
791		Therefor, in our template we put a non-breaking-space in the place of the combobox html.
792		BUT what about that those form tage that surround this combobox, we should leave them out
793		too. In typical templaying this is ease to replace the form opening tag with a non-breaking-space.
794		BUT the closing tag is such a simple thing we often hard code it into the template, not a template
795		var. SO we can not leave out the form open tag but have the form close tag still be in the template.
796		This no-brainer function just makes it easy to remember to leave out or include, as the case may
797		be, the form closeing tag.
798		@access public
799		*/
800		function form_closetag()
801		{
802			return '</form>';
803		}
804
805		/**************************************************************************\
806		*	BUTTON WIDGET
807		\**************************************************************************/
808
809		/*!
810		@function make_button
811		@abstract generate a button in a SINGLE FUNCTION CALL, all params must be passed.
812		@author Angles
813		@param $type (string) usually "SUBMIT"
814		@param $name (string) they GPC "key" in the "key - value" pair
815		@param $value (string) they GPC "value" in the "key - value" pair AND THE TEXT on the button
816		@param $onClick (string) OPTIONAL usually some javascript for the onclick event of the button. Default is none
817		@discussion Since a button is generally considered a "widget", I will call this a widget although it does
818		not use "set_" property functions the other widgets do. All params must be passed in the function call.
819		@access public
820		@example $my_button = $this->widgets->make_button('submit', 'btn_send', lang('Send'));
821		*/
822		//<input type="submit" name="btn_send" value="Send">
823		function make_button($type='', $name='',$value='', $onClick='')
824		{
825			if ($type == '')
826			{
827				$type='submit';
828			}
829			if ($name == '')
830			{
831				$name=$type.'_button';
832			}
833			if ($value == '')
834			{
835				$value=lang('submit');
836			}
837			if ($onClick == '')
838			{
839				$onClick_tag = '';
840			}
841			else
842			{
843				$onClick_tag = ' onClick="'.$onClick.'"';;
844			}
845
846			$button = '<input type="'.$type.'" name="'.$name.'" value="'.$value.'"'.$onClick_tag.'>';
847			return $button;
848		}
849
850		/**************************************************************************\
851		*	TOOLBAR COMPOUND WIDGET
852		\**************************************************************************/
853
854		/*!
855		@capability TOOLBAR COMPOUND WIDGET
856		@discussion generate a toolbar for use in email pages  NOTE: usually only one toolbar made per page view
857		so there is no "new_toolbar" function because we should not need it. set_toolbar_msg is the only value
858		that you might want to check if you make more then one toolbar.
859		@author Angles
860		*/
861
862		/*!
863		@function set_toolbar_msg
864		@abstract the toolbar has a 3rd row which can display text to the user. This function sets that.
865		@param $msg (string)
866		@author Angles
867		@discussion Usually after deleting or moving messages or creating, renaming, or deleting folders,
868		the mail_msg generates some kind of message to report to the user what actions were just taken.
869		Note a blank string will clear a msg if needed. Currently only the uiindex page and the uifolder page
870		might provide a msg.
871		@access public
872		*/
873		function set_toolbar_msg($msg='')
874		{
875			$this->toolbar_msg = $msg;
876		}
877		/*!
878		@function get_toolbar_msg
879		@abstract get whatever value the toolbar_msg property has.
880		@author Angles
881		@access public
882		*/
883		function get_toolbar_msg()
884		{
885			return $this->toolbar_msg;
886		}
887
888		/*!
889		@function get_toolbar
890		@abstract this function returns a complete html toolbar widget that is on top of many email pages.
891		@author Angles
892		@discussion generate a toolbar for use in email pages  NOTE:
893		WE NEED globals[phpge]->msg OBJECT and A LOGIN in order to make this toolbar,
894		THEREFOR do not put this toolbar on a page where login may not be available.Currently,
895		Preferencs pages DO NOT LOGIN, because if you are setting preferences you do not need
896		a mailserver stream AND you may not even have enough data set to get a mailserver stream.
897		Note: uses a private template object to assemple the toolbar, calling function is responsible for
898		putting the result in the global template.
899		@access public
900		*/
901		function get_toolbar()
902		{
903			// WE NEED ->msg OBJECT and A LOGIN in order to make this toolbar
904			$this->msg_bootstrap = CreateObject("email.msg_bootstrap");
905			$this->msg_bootstrap->ensure_mail_msg_exists('emai.html_widgets.get_toolbar', 0);
906
907			// we use a PRIVATE template object to produce this toolbar
908			$this->tpl = CreateObject('phpgwapi.Template',PHPGW_APP_TPL);
909
910			// if we already made this toolbar, retuen it from L1 cache ????
911			//$my_acctnum = $GLOBALS['phpgw']->msg->get_acctnum();
912			$this->tpl->set_file(array('T_widget_toolbar' => 'widget_toolbar.tpl'));
913			$this->tpl->set_block('T_widget_toolbar','B_toolbar_row_one','V_toolbar_row_one');
914			$this->tpl->set_block('T_widget_toolbar','B_toolbar_row_two','V_toolbar_row_two');
915
916			// We use these over and over, so figure them out now
917			// some fonts and font sizes
918			$row1_rowcolor_key = 'row_off';
919			$row2_rowcolor_key = 'row_on';
920			$this->tpl->set_var('row1_rowcolor_key',$row1_rowcolor_key);
921			$this->tpl->set_var('row2_rowcolor_key',$row2_rowcolor_key);
922			$this->tpl->set_var('toolbar_row1_bgcolor',$GLOBALS['phpgw_info']['theme'][$row1_rowcolor_key]);
923			$this->tpl->set_var('toolbar_row2_bgcolor',$GLOBALS['phpgw_info']['theme'][$row2_rowcolor_key]);
924			$this->tpl->set_var('toolbar_font',$GLOBALS['phpgw_info']['theme']['font']);
925			$this->tpl->set_var('toolbar_font_size','2');
926			$this->tpl->set_var('report_this_font_size','1');
927
928			$this->tpl->set_var('report_this', $GLOBALS['phpgw']->msg->report_moved_or_deleted());
929
930			$icon_theme = $GLOBALS['phpgw']->msg->get_pref_value('icon_theme',$acctnum);
931			$icon_size = $GLOBALS['phpgw']->msg->get_pref_value('icon_size',$acctnum);
932			$svr_image_dir = PHPGW_IMAGES_DIR;
933			$image_dir = PHPGW_IMAGES;
934
935			// this is optional
936			$this->clear_href_vars();
937			// Create Links for all the buttons
938			$folders_link = $GLOBALS['phpgw']->link('/index.php',array(
939									'menuaction' => 'email.uifolder.folder',
940									// going to the folder list page, we only need log into the INBOX folder
941									'fldball[folder]' => 'INBOX',
942									'fldball[acctnum]' => $GLOBALS['phpgw']->msg->get_acctnum()));
943			$compose_link = $GLOBALS['phpgw']->link('/index.php',array(
944									'menuaction' => 'email.uicompose.compose',
945									// this data tells us where to return to after sending a message
946									'fldball[folder]' => $GLOBALS['phpgw']->msg->prep_folder_out(),
947									'fldball[acctnum]' => $GLOBALS['phpgw']->msg->get_acctnum(),
948									'sort' => $GLOBALS['phpgw']->msg->get_arg_value('sort'),
949									'order' => $GLOBALS['phpgw']->msg->get_arg_value('order'),
950									'start' => $GLOBALS['phpgw']->msg->get_arg_value('start')));
951			$search_link = $GLOBALS['phpgw']->link('/index.php', array(
952									'menuaction' => 'email.uisearch.form',
953									// this data tells us what account we are operating in
954									'fldball[folder]' => $GLOBALS['phpgw']->msg->prep_folder_out(),
955									'fldball[acctnum]' => $GLOBALS['phpgw']->msg->get_acctnum()
956));
957
958			$filters_link = $GLOBALS['phpgw']->link('/index.php',array(
959								'menuaction' => 'email.uifilters.filters_list',
960								// this data tells us what folder and account was last active
961								'fldball[folder]' => $GLOBALS['phpgw']->msg->prep_folder_out(),
962								'fldball[acctnum]' => $GLOBALS['phpgw']->msg->get_acctnum()));
963			$accounts_link = $GLOBALS['phpgw']->link('/index.php','menuaction=email.uipreferences.ex_accounts_list');
964			$email_prefs_link = $GLOBALS['phpgw']->link('/index.php',array(
965								'menuaction' => 'email.uipreferences.preferences',
966								'ex_acctnum' => $GLOBALS['phpgw']->msg->get_acctnum()));
967			// Check to see if mailserver supports folders.
968			$has_folders = $GLOBALS['phpgw']->msg->get_mailsvr_supports_folders();
969			// Create Buttons
970			switch ($GLOBALS['phpgw']->msg->get_pref_value('button_type'))
971			{
972				case 'text':
973					//Create Compose Button
974					$this->set_href_link($compose_link);
975					$this->set_href_clickme(lang('Compose'));
976					$this->tpl->set_var('compose_txt_link', $this->get_href());
977					$this->tpl->set_var('compose_img_link', '&nbsp;');
978					//Create Search Button
979					$this->set_href_link($search_link);
980					$this->set_href_clickme(lang('Search'));
981					$this->tpl->set_var('search_txt_link', $this->get_href());
982					$this->tpl->set_var('search_img_link', '&nbsp;');
983					//Create Filter Button
984					$this->set_href_link($filters_link);
985					$this->set_href_clickme(lang('Filters'));
986					$this->tpl->set_var('filters_txt_link', $this->get_href());
987					$this->tpl->set_var('filters_img_link', '&nbsp;');
988					//Create Accounts Button
989					$this->set_href_link($accounts_link);
990					$this->set_href_clickme(lang('Accounts'));
991					$this->tpl->set_var('accounts_txt_link', $this->get_href());
992					$this->tpl->set_var('accounts_img_link', '&nbsp;');
993					//Create Settings Button
994					$this->set_href_link($email_prefs_link);
995					$this->set_href_clickme(lang('Settings'));
996					$this->tpl->set_var('settings_txt_link', $this->get_href());
997					$this->tpl->set_var('settings_img_link', '&nbsp;');
998					//Check for folder support and create Folder Button
999					if ($has_folders == True)
1000					{
1001						//$this->set_href_clickme($this->img_maketag($image_dir.'/'.$icon_theme.'-folder-'.$icon_size.'.gif',lang('Folders'),'','','0'));
1002						//$this->tpl->set_var('folders_img_link', $this->get_href());
1003						//Create Folder Text Link
1004						$this->set_href_link($folders_link);
1005						$this->set_href_clickme(lang('Folders'));
1006						$this->tpl->set_var('folders_txt_link', $this->get_href());
1007						$this->tpl->set_var('folders_img_link', '&nbsp;');
1008					}
1009					else
1010					{
1011						$this->tpl->set_var('folders_img_link', '&nbsp;');
1012						$this->tpl->set_var('folders_txt_link', '&nbsp;');
1013					}
1014					break;
1015				case 'image':
1016					//Create Compose Button
1017					$this->set_href_link($compose_link);
1018					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/compose-message-'.$icon_size,'_on'),lang('Compose'),'','','0'));
1019					$this->tpl->set_var('compose_img_link', $this->get_href());
1020					$this->tpl->set_var('compose_txt_link', '&nbsp;');
1021					//Create Search Button
1022					$this->set_href_link($search_link);
1023					//$this->set_href_clickme($this->img_maketag($image_dir.'/'.$icon_theme.'-search-16.gif',lang('Search'),'','','0'));
1024					// will fix this later when new images are made
1025					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/search-'.$icon_size,'_on'),lang('Search'),'','','0'));
1026					$this->tpl->set_var('search_img_link', $this->get_href());
1027					$this->tpl->set_var('search_txt_link', '&nbsp;');
1028					//Create Filter Button
1029					$this->set_href_link($filters_link);
1030					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/filters-'.$icon_size,'_on'),lang('Filters'),'','','0'));
1031					$this->tpl->set_var('filters_img_link', $this->get_href());
1032					$this->tpl->set_var('filters_txt_link', '&nbsp;');
1033					//Create Accounts Button
1034					$this->set_href_link($accounts_link);
1035					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/accounts-'.$icon_size,'_on'),lang('Accounts'),'','','0'));
1036					$this->tpl->set_var('accounts_img_link', $this->get_href());
1037					$this->tpl->set_var('accounts_txt_link', '&nbsp;');
1038					//Create Settings Button
1039					$this->set_href_link($email_prefs_link);
1040					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/customize-'.$icon_size,'_on'),lang('Settings'),'','','0'));
1041					$this->tpl->set_var('settings_img_link', $this->get_href());
1042					$this->tpl->set_var('settings_txt_link', '&nbsp;');
1043					//Check for folder support and create Folder Button
1044					if ($has_folders == True)
1045					{
1046						//Create Folder Image Link
1047						$this->set_href_link($folders_link);
1048						$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/folder-'.$icon_size,'_on'),lang('Folders'),'','','0'));
1049						$this->tpl->set_var('folders_img_link', $this->get_href());
1050						$this->tpl->set_var('folders_txt_link', '&nbsp;');
1051
1052					}
1053					else
1054					{
1055						$this->tpl->set_var('folders_txt_link', '&nbsp;');
1056						$this->tpl->set_var('folders_txt_link', '&nbsp;');
1057					}
1058					break;
1059				case 'both':
1060					//Create Compose Button
1061					$this->set_href_link($compose_link);
1062					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/compose-message-'.$icon_size,'_on'),lang('Compose'),'','','0'));
1063					$this->tpl->set_var('compose_img_link', $this->get_href());
1064					$this->set_href_link($compose_link);
1065					$this->set_href_clickme(lang('Compose'));
1066					$this->tpl->set_var('compose_txt_link', $this->get_href());
1067					//Create Search Button
1068					$this->set_href_link($search_link);
1069					//$this->set_href_clickme($this->img_maketag($image_dir.'/'.$icon_theme.'-search-16.gif',lang('Search'),'','','0'));
1070					// will fix this later when new images are made
1071					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/search-'.$icon_size,'_on'),lang('Search'),'','','0'));
1072					$this->tpl->set_var('search_img_link', $this->get_href());
1073					$this->set_href_link($search_link);
1074					$this->set_href_clickme(lang('Search'));
1075					$this->tpl->set_var('search_txt_link', $this->get_href());
1076					//Create Filter Button
1077					$this->set_href_link($filters_link);
1078					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/filters-'.$icon_size,'_on'),lang('Filters'),'','','0'));
1079					$this->tpl->set_var('filters_img_link', $this->get_href());
1080					$this->set_href_link($filters_link);
1081					$this->set_href_clickme(lang('Filters'));
1082					$this->tpl->set_var('filters_txt_link', $this->get_href());
1083					//Create Accounts Button
1084					$this->set_href_link($accounts_link);
1085					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/accounts-'.$icon_size,'_on'),lang('Accounts'),'','','0'));
1086					$this->tpl->set_var('accounts_img_link', $this->get_href());
1087					$this->set_href_link($accounts_link);
1088					$this->set_href_clickme(lang('Accounts'));
1089					$this->tpl->set_var('accounts_txt_link', $this->get_href());
1090					//Create Settings Button
1091					$this->set_href_link($email_prefs_link);
1092					$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/customize-'.$icon_size,'_on'),lang('Settings'),'','','0'));
1093					$this->tpl->set_var('settings_img_link', $this->get_href());
1094					$this->set_href_link($email_prefs_link);
1095					$this->set_href_clickme(lang('Settings'));
1096					$this->tpl->set_var('settings_txt_link', $this->get_href());
1097					//Check for folder support and create Folder Button
1098					if ($has_folders == True)
1099					{
1100						//Create Folder Image Link
1101						$this->set_href_link($folders_link);
1102						$this->set_href_clickme($this->img_maketag($GLOBALS['phpgw']->msg->_image_on('email',$icon_theme.'/folder-'.$icon_size,'_on'),lang('Folders'),'','','0'));
1103						$this->tpl->set_var('folders_img_link', $this->get_href());
1104						//Create Folder Text Link
1105						$this->set_href_link($folders_link);
1106						$this->set_href_clickme(lang('Folders'));
1107						$this->tpl->set_var('folders_txt_link', $this->get_href());
1108					}
1109					else
1110					{
1111						$this->tpl->set_var('folders_img_link', '&nbsp;');
1112						$this->tpl->set_var('folders_txt_link', '&nbsp;');
1113					}
1114					break;
1115				}
1116			// WAIT if this is NOT IMAP then we can NOT search
1117			// use the has_folders var from above, it should be a good enough indicator
1118			if ($has_folders == False)
1119			{
1120					$this->tpl->set_var('search_img_link', '&nbsp;');
1121					$this->tpl->set_var('search_txt_link', '&nbsp;');
1122			}
1123			// make the 1st row
1124			$this->toolbar_row_one = $this->tpl->parse('V_toolbar_row_one','B_toolbar_row_one');
1125			// END TOOL BAR ROW 1
1126
1127			// BEGIN TOOL BAR ROW2
1128			// ---- folders switchbox  ----
1129			//<form name="folders_cbox" action="/mail/index.php?menuaction=email.uiindex.index" method="post">
1130			if ($has_folders == True)
1131			{
1132				$this->new_form();
1133				$this->set_form_name('folders_cbox');
1134				$this->set_form_action($GLOBALS['phpgw']->link('/index.php','menuaction=email.uiindex.index'));
1135				$this->set_form_method('post');
1136				$this->tpl->set_var('form_folders_cbox_opentag', $this->get_form());
1137				$this->tpl->set_var('folders_combobox', $this->all_folders_combobox());
1138				$this->tpl->set_var('form_folders_cbox_closetag', $this->form_closetag());
1139			}
1140			else
1141			{
1142				$this->tpl->set_var('form_folders_cbox_opentag', '');
1143				$this->tpl->set_var('folders_combobox', '&nbsp;');
1144				$this->tpl->set_var('form_folders_cbox_closetag', '');
1145			}
1146			// associated image is still filled from row one
1147
1148
1149			// ---- account switchbox  ----
1150			// <form name="acctbox" action="/mail/index.php?menuaction=email.uiindex.index" method="post">
1151			$this->new_form();
1152			$this->set_form_name('accounts_cbox');
1153			$this->set_form_action($GLOBALS['phpgw']->link('/index.php','menuaction=email.uiindex.index'));
1154			$this->set_form_method('post');
1155			$this->tpl->set_var('form_acctbox_opentag', $this->get_form());
1156			$this->tpl->set_var('acctbox_combobox', $this->all_accounts_combobox());
1157			// associated image is still filled from row one
1158
1159			// show he user a message if this property is filled, if empty then output a nbsp for html sanity
1160			if (trim($this->get_toolbar_msg()) != '')
1161			{
1162				$toolbar_report_msg = $this->get_toolbar_msg();
1163			}
1164			else
1165			{
1166				$toolbar_report_msg = '&nbsp;';
1167			}
1168			$this->tpl->set_var('toolbar_report_msg', $toolbar_report_msg);
1169
1170
1171			// make the 2nd row AND the 3rd row
1172			$this->toolbar_row_two = $this->tpl->parse('V_toolbar_row_two','B_toolbar_row_two');
1173
1174			return $this->toolbar_row_one . $this->toolbar_row_two;
1175
1176		}
1177
1178
1179		/*!
1180		@function all_folders_combobox
1181		@abstract high level function, uses functions in mail_msg and this class html_widgets to make an acct switchbox
1182		UNDER DEVELOPMENT.
1183		@param $form_reference (string) this bombobox sets an "onChange" event, which will submit the form you put here.
1184		Default value is "document.folders_cbox.submit()" where "folders_cbox" is the default value
1185		for the $form_reference param.
1186		@param $is_move_box (boolean) OPTIONAL default is False, use is making a Move Messages To combo box,
1187		which requires a different cbox name and different first line text.
1188		@result string representing an HTML listbox widget
1189		@author Angles
1190		@discussion The first item in this folder combo box tells the user to "pick a folder to change to", and has
1191		no "value", the value is an empty string, this is more like a label than a combobox item.
1192		@access private, maybe made public
1193		*/
1194		function all_folders_combobox($form_reference='',$is_move_box=False,$skip_fldball='',$first_line_txt='')
1195		{
1196			if ($form_reference == '')
1197			{
1198				$form_reference = 'folders_cbox';
1199			}
1200			$acctnum = $GLOBALS['phpgw']->msg->get_acctnum();
1201
1202			$this->new_combobox();
1203			if ($is_move_box)
1204			{
1205				// right now ONLY the "Move Message To" combo box needs to use this
1206				$this->set_cbox_name('to_fldball_fake_uri');
1207				$this->set_cbox_onChange('do_action(\'move\')');
1208				if ($first_line_txt)
1209				{
1210					// right now ONLY the Message View page "Move This Message To" combo box uses this
1211					$this->set_cbox_item('', $first_line_txt);
1212				}
1213				else
1214				{
1215					$this->set_cbox_item('', lang('move selected messages into'));
1216				}
1217			}
1218			else
1219			{
1220				$this->set_cbox_name('fldball_fake_uri');
1221				// default is "document.folders_cbox.submit()"
1222				$this->set_cbox_onChange('document.'.$form_reference.'.submit()');
1223				// set_cbox_item(value, text, selected(optional, boolean, default false)
1224				$this->set_cbox_item('', lang('switch current folder to'));
1225			}
1226
1227			// get the actual list of folders we are going to put into the combobox
1228			//$folder_list = $GLOBALS['phpgw']->msg->get_folder_list();
1229			$folder_list = $GLOBALS['phpgw']->msg->get_arg_value('folder_list', $acctnum);
1230			//$folder_list =& $GLOBALS['phpgw']->msg->get_arg_value_ref('folder_list');
1231
1232			$listbox_show_unseen = $GLOBALS['phpgw']->msg->get_isset_pref('newmsg_combobox', $acctnum);
1233
1234			for ($i=0; $i<count($folder_list);$i++)
1235			{
1236				// folder long needs urlencoding ONCE, string can NOT be plain and can NOT be urlencoded more once.
1237				//$folder_long = $GLOBALS['phpgw']->msg->ensure_one_urlencoding($folder_list[$i]['folder_long']);
1238				$folder_long = $GLOBALS['phpgw']->msg->prep_folder_out($folder_list[$i]['folder_long']);
1239				// for display to the user, if this is the INBOX, then translate that using lang INBOX
1240				if ($folder_list[$i]['folder_short'] == 'INBOX')
1241				{
1242				    //$folder_short = lang('INBOX');
1243					// try this for common folder related lang strings
1244					$folder_short = $GLOBALS['phpgw']->msg->get_common_langs('lang_inbox');
1245				}
1246				else
1247				{
1248					// not inINBOX, so use actual folder name, no translation for the user is done
1249					$folder_short = $folder_list[$i]['folder_short'];
1250				}
1251				$folder_acctnum = $folder_list[$i]['acctnum'];
1252				$skip_me = False;
1253				if ($skip_fldball)
1254				{
1255					// move folder lists usually skip the current folder because you can not move to current folder
1256					if (($skip_fldball['folder'] == $folder_long)
1257					&& ($skip_fldball['acctnum'] == $acctnum))
1258					{
1259						$skip_me = True;
1260					}
1261				}
1262				if ($skip_me)
1263				{
1264					continue;
1265				}
1266
1267				if ($listbox_show_unseen == True)
1268				{
1269					$tmp_fldball = array();
1270					$tmp_fldball['folder'] = $folder_long;
1271					$tmp_fldball['acctnum'] = $folder_acctnum;
1272					$folder_status = $GLOBALS['phpgw']->msg->get_folder_status_info($tmp_fldball);
1273					$folder_unseen = number_format($folder_status['number_new']);
1274					$tmp_fldball = array();
1275				}
1276
1277				// set_cbox_item(value, text, selected(optional, boolean, default false)
1278				if ($listbox_show_unseen == True)
1279				{
1280					$this->set_cbox_item('&folder='.$folder_long.'&acctnum='.$folder_acctnum, $folder_short . ' (' . $folder_unseen . ')');
1281				}
1282				else
1283				{
1284					$this->set_cbox_item('&folder='.$folder_long.'&acctnum='.$folder_acctnum, $folder_short);
1285				}
1286			}
1287			return $this->get_combobox();
1288
1289		}
1290
1291
1292		/*!
1293		@function all_folders_mega_combobox
1294		@abstract high level function, uses functions in mail_msg and this class html_widgets to make a listbox for
1295		all folders in all accounts.  DEPRECIATED.
1296		@param $form_reference (string) this combobox sets an "onChange" event, which will submit the form you put here.
1297		Default value is "document.folders_cbox.submit()" where "" is the default value for the $form_reference param.
1298		DEPRECIATED in favor of all_folders_megalist.
1299		@result string representing an HTML listbox widget
1300		@author Angles
1301		@discussion ?
1302		@access private, maybe made public
1303		*/
1304		function all_folders_mega_combobox_OLD($form_reference='')
1305		{
1306				$feed_args = Array(
1307					'mailsvr_stream'	=> '',
1308					'pre_select_folder'	=> $pre_select_folder,
1309					'pre_select_folder_acctnum' => $pre_select_folder_acctnum,
1310					'skip_folder'		=> '',
1311					'show_num_new'		=> $listbox_show_unseen,
1312					'widget_name'		=> $folder_listbox_name,
1313					'folder_key_name'	=> 'folder',
1314					'acctnum_key_name'	=> 'acctnum',
1315					'on_change'			=> '',
1316					'first_line_txt'	=> lang('if fileto then select destination folder')
1317				);
1318				$folder_listbox = $GLOBALS['phpgw']->msg->folders_mega_listbox($feed_args);
1319		}
1320
1321		/*!
1322		@function new_all_folders_megalist
1323		@abstract Resets all Properties all_folders_megalist
1324		@discussion Delphi style OOP property GetSet functions are used, this resets them all.
1325		@author Angles
1326		*/
1327		function new_all_folders_megalist()
1328		{
1329				$this->F_megalist_form_reference = '';
1330				// this is the only think that actually needs a value
1331				$this->F_megalist_widget_name = 'not_provided';
1332				$this->F_megalist_preselected_fldball = '';
1333				$this->F_megalist_skip_fldball = '';
1334				// the first item can be used to display instructional text to the user
1335				$this->F_megalist_first_item_text = '';
1336		}
1337
1338		/*!
1339		@function prop_megalist_form_reference
1340		@abstract Property function form_reference for folders_mega_listbox, form_reference is used in onChange JS.
1341		@discussion Delphi style OOP property GetSet function.
1342		@author Angles
1343		*/
1344		function prop_megalist_form_reference($form_reference='')
1345		{
1346			if ($form_reference)
1347			{
1348				$this->F_megalist_form_reference = $form_reference;
1349			}
1350			return $this->F_megalist_form_reference;
1351		}
1352
1353		/*!
1354		@function prop__megalist_widget_name
1355		@abstract Property function widget name for folders_mega_listbox
1356		@discussion Delphi style OOP property GetSet function.
1357		@author Angles
1358		*/
1359		function prop_megalist_widget_name($widget_name='')
1360		{
1361			if ($widget_name)
1362			{
1363				$this->F_megalist_widget_name = $widget_name;
1364			}
1365			return $this->F_megalist_widget_name;
1366		}
1367
1368		/*!
1369		@function prop_megalist_preselected_fldball
1370		@abstract Property function preselected folder (in fldball form) for folders_mega_listbox
1371		@discussion Delphi style OOP property GetSet function.
1372		@author Angles
1373		*/
1374		function prop_megalist_preselected_fldball($fldball='')
1375		{
1376			if ((isset($fldball))
1377			&& ($fldball['folder'] != '')
1378			&& ((string)$fldball['acctnum'] != ''))
1379			{
1380				$this->F_megalist_preselected_fldball = $fldball;
1381			}
1382			return $this->F_megalist_preselected_fldball;
1383		}
1384
1385		/*!
1386		@function prop_megalist_skip_fldball
1387		@abstract Property function folder (in fldball form) to NOT show in the folders_mega_listbox
1388		@discussion Delphi style OOP property GetSet function.
1389		@author Angles
1390		*/
1391		function prop_megalist_skip_fldball($fldball='')
1392		{
1393			if ((isset($fldball))
1394			&& ($fldball['folder'] != '')
1395			&& ((string)$fldball['acctnum'] != ''))
1396			{
1397				$this->F_megalist_skip_fldball = $fldball;
1398			}
1399			return $this->F_megalist_skip_fldball;
1400		}
1401
1402		/*!
1403		@function prop__megalist_widget_name
1404		@abstract Property function for folders_mega_listbox, the first item can be used to display instructional text to the user
1405		@discussion Delphi style OOP property GetSet function.
1406		@author Angles
1407		*/
1408		function prop_megalist_first_item_text($first_item_text='')
1409		{
1410			if ($first_item_text)
1411			{
1412				$this->F_megalist_first_item_text = $first_item_text;
1413			}
1414			return $this->F_megalist_first_item_text;
1415		}
1416
1417		/*!
1418		@function all_folders_megalist
1419		@abstract All accounts All Folders in a html listbox
1420		@discussion UNDER DEVELOPMENT, right now the leading candidate to be THE folder list
1421		function, but now sure yet.
1422		@author Angles
1423		*/
1424		function all_folders_megalist()
1425		{
1426			$debug_mega_listbox = 0;
1427			//$debug_mega_listbox = 3;
1428
1429			if ($debug_mega_listbox > 0) { echo 'folders_mega_listbox('.__LINE__.'): ENTERING<br />'; }
1430
1431			$this->new_combobox();
1432			$this->set_cbox_name($this->F_megalist_widget_name);
1433
1434			// there is NO ON change right now, this is currently used on the filters page, we do not need action onChange there
1435			// default is "document.mega_folders_cbox.submit()"
1436			//$this->set_cbox_onChange('document.'.$form_reference.'.submit()');
1437
1438			// set_cbox_item(value, text, selected(optional, boolean, default false)
1439			if ($this->F_megalist_first_item_text)
1440			{
1441				$this->set_cbox_item('', $this->F_megalist_first_item_text);
1442			}
1443
1444			// we need the loop to include the default account AS WELL AS the extra accounts
1445			for ($x=0; $x < count($GLOBALS['phpgw']->msg->extra_and_default_acounts); $x++)
1446			{
1447				$this_acctnum = $GLOBALS['phpgw']->msg->extra_and_default_acounts[$x]['acctnum'];
1448				$this_status = $GLOBALS['phpgw']->msg->extra_and_default_acounts[$x]['status'];
1449				// do not enable this yet, maybe later
1450				//$listbox_show_unseen = $GLOBALS['phpgw']->msg->get_isset_pref('newmsg_combobox', $acctnum);
1451				$listbox_show_unseen = False;
1452				if ($this_status != 'enabled')
1453				{
1454					// Do Nothing, This account is not in use
1455					if ($debug_mega_listbox > 1) { echo 'folders_mega_listbox('.__LINE__.'): $this_acctnum ['.$this_acctnum.'] is not in use, so skip folderlist<br />'; }
1456				}
1457				else
1458				{
1459					$folder_list = $GLOBALS['phpgw']->msg->get_arg_value('folder_list', $this_acctnum);
1460					if ($debug_mega_listbox > 1) { echo 'folders_mega_listbox('.__LINE__.'): $this_acctnum ['.$this_acctnum.'] IS enabled, got folder list<br />'; }
1461					if ($debug_mega_listbox > 2) { echo 'folders_mega_listbox('.__LINE__.'): $folder_list for $this_acctnum ['.$this_acctnum.'] DUMP<pre>'; print_r($folder_list); echo '</pre>'; }
1462
1463					// iterate thru the folder list for this acctnum
1464					for ($i=0; $i<count($folder_list);$i++)
1465					{
1466						$folder_long = $folder_list[$i]['folder_long'];
1467						$folder_long_preped_out = $GLOBALS['phpgw']->msg->prep_folder_out($folder_long);
1468						$folder_short = $folder_list[$i]['folder_short'];
1469						// yes we need $folder_acctnum to help make the "folder ball", yes I know it *should* be the same as $this_acctnum
1470						$folder_acctnum = $folder_list[$i]['acctnum'];
1471
1472						// this logic determines we should not include a certain folder in the combobox list
1473						if (($this->F_megalist_skip_fldball)
1474						&& ($folder_long_preped_out == $this->F_megalist_skip_fldball['folder'])
1475						&& ($folder_acctnum == $this->F_megalist_skip_fldball['acctnum']))
1476						{
1477							// Do Nothing, this folder should not be included
1478							if ($debug_mega_listbox > 1) { echo 'folders_mega_listbox('.__LINE__.'): skipping $this->F_megalist_skip_fldball ['.htmlspecialchars(serialize($this->F_megalist_skip_fldball)).'] has been matched<br />'; }
1479						}
1480						else
1481						{
1482							// this logic determines if the combobox should be initialized with certain folder already selected
1483							// we use "folder short" as the comparator because that way at least we know we are comparing syntatic-ally similar items
1484							if (($this->F_megalist_preselected_fldball)
1485							&& ($folder_long_preped_out == $this->F_megalist_preselected_fldball['folder'])
1486							&& ($folder_acctnum == $this->F_megalist_preselected_fldball['acctnum']))
1487							{
1488								$preselected = True;
1489							}
1490							else
1491							{
1492								$preselected = False;
1493							}
1494
1495							if ($listbox_show_unseen == True)
1496							{
1497								$tmp_fldball = array();
1498								$tmp_fldball['folder'] = $folder_long;
1499								$tmp_fldball['acctnum'] = $folder_acctnum;
1500								$folder_status = $GLOBALS['phpgw']->msg->get_folder_status_info($tmp_fldball);
1501								$folder_unseen = number_format($folder_status['number_new']);
1502								// complete the text here so we do not need another if ... then below
1503								$folder_unseen = ' ('. $folder_unseen.')';
1504								$tmp_fldball = array();
1505							}
1506							else
1507							{
1508								$folder_unseen = '';
1509							}
1510
1511							$option_value = '&folder='.$folder_long_preped_out.'&acctnum='.$folder_acctnum;
1512							//$option_value =	'&folder='.$folder_long.'&acctnum='.$folder_acctnum;
1513							// if $folder_unseen has anything it gets added to the string here
1514							$text_blurb = '['.$folder_acctnum.'] '.$folder_short.$folder_unseen;
1515
1516							// set_cbox_item(value, text, selected(optional, boolean, default false)
1517							$this->set_cbox_item($option_value, $text_blurb, $preselected);
1518						}
1519					}
1520				}
1521			}
1522			if ($debug_mega_listbox > 0) { echo 'folders_mega_listbox('.__LINE__.'): LEAVING<br />'; }
1523			return $this->get_combobox();
1524		}
1525
1526
1527
1528		/*!
1529		@function all_accounts_combobox
1530		@abstract UNDER DEVELOPMENT
1531		@author Angles
1532		@discussion the "values" are in the form of a URI request string, since a combobox can
1533		only submit a single string as its value. This way we put alot of information if the form
1534		of the URI request and use php function "parse_str" to "recover" all this data on the submit.
1535		Accounts have a "status" associated with them, can be "enabled", "disabled", or "empty".
1536		In this combobox we show "enabled" and "disabled" accounts, not "empty" accounts.
1537		NOTE "disabled" really has no use, and "empty" I am not sure if that is ever used anywhere at all.
1538		Also note that a "disabled" account should never be "pre-selected" in this combobox, which seems logical.
1539		Almost always there is an email account that can be considered "active" because the user is viewing its
1540		data (folders, messages, its preferences) or if the user is composing a message then the last "active"
1541		account is considered the account which this mail will be "from". Therefor, generally all mail activity
1542		have an account that it applies to. So when this combobox comes across the account that is currently
1543		"active", that account will be "pre-selected" in the combobox. This serves two purposes, ONE, the user
1544		can not swicth to an account that is currently the "active" account, the user can only switch do
1545		a different account, and TWO, this gives the user visual feedback about which account is currently
1546		"active", on some pages, such as the compose page, this remines the user who the mail will be "from",
1547		i.e. which account sent the mail. In making this thing we iterate thru the "extra_and_default_acounts list",
1548		which is an numbered array whose members are structured array data describing the account.
1549		*/
1550		function all_accounts_combobox()
1551		{
1552			// $GLOBALS['phpgw']->msg->ex_accounts_count
1553			// $GLOBALS['phpgw']->msg->extra_accounts
1554
1555			//$debug_widget = True;
1556			$debug_widget = False;
1557			$acctnum = $GLOBALS['phpgw']->msg->get_acctnum();
1558
1559			$this->new_combobox();
1560			$this->set_cbox_name('fldball_fake_uri');
1561			$this->set_cbox_onChange('document.accounts_cbox.submit()');
1562
1563			for ($i=0; $i < count($GLOBALS['phpgw']->msg->extra_and_default_acounts); $i++)
1564			{
1565				$this_acctnum = $GLOBALS['phpgw']->msg->extra_and_default_acounts[$i]['acctnum'];
1566				$this_acct_status = $GLOBALS['phpgw']->msg->extra_and_default_acounts[$i]['status'];
1567				$this_acct_fullname = $GLOBALS['phpgw']->msg->get_pref_value('fullname', $this_acctnum);
1568
1569				if ($this_acct_status == 'disabled')
1570				{
1571					// set_cbox_item(value, text, selected(optional, boolean, default false)
1572					$this->set_cbox_item('&folder=INBOX&acctnum=0',
1573						lang('account').' ['.$this_acctnum.'] '.lang('disabled'));
1574				}
1575				elseif ($this_acct_status == 'enabled')
1576				{
1577					// set_cbox_item(value, text, selected(optional, boolean, default false)
1578					if ($GLOBALS['phpgw']->msg->get_pref_value('account_name', $this_acctnum))
1579					{
1580						$this->set_cbox_item('&folder=INBOX&acctnum='.$this_acctnum,
1581						$GLOBALS['phpgw']->msg->get_pref_value('account_name', $this_acctnum),
1582						((string)$acctnum == (string)$this_acctnum));
1583
1584					} else {
1585						$this->set_cbox_item('&folder=INBOX&acctnum='.$this_acctnum,
1586							lang('account').' '.$this_acctnum.':  '.$this_acct_fullname,
1587							((string)$acctnum == (string)$this_acctnum));
1588					}
1589				}
1590			}
1591			return $this->get_combobox();
1592		}
1593
1594		/*!
1595		@function auto_refresh
1596		@example I know of 3 ways to get a page to reload, 2 of those ways are pretty much the same
1597		1. the http header
1598			Refresh: 5;
1599		2. the META http-equiv
1600			&lt;META HTTP-EQUIV="Refresh" CONTENT="60"&gt>
1601		both 1 and 2 have the same effect as hitting the "reload" button, which in *many* browsers will
1602		force a re-download of all the images on the page, i.e. the browser will NOT use the cached images
1603		3. java script combo of "window.setTimeout" with "window.location"
1604			window.setTimeout('window.location="http://example.com/phpgw/email/index.php"; ',1800000);
1605		method 3 is the only one I know of that will use the images from the cache.
1606		also, 3 takes a reload value in miliseconds, so a value of 180000 is really 3 minutes
1607		ALSO, use if..then code to only auto-refresh certain pages, such as email/index.php
1608		@author Angles
1609		*/
1610		function auto_refresh($reload_me='', $feed_refresh_ms='')
1611		{
1612			if ($GLOBALS['phpgw']->msg->get_isset_pref('refresh_ms'))
1613			{
1614				$pref_refresh_ms = $GLOBALS['phpgw']->msg->get_pref_value('refresh_ms');
1615			}
1616			else
1617			{
1618				$pref_refresh_ms = '';
1619			}
1620			// which do we use
1621			$refresh_ms = '';
1622			if ($feed_refresh_ms)
1623			{
1624				$refresh_ms = $feed_refresh_ms;
1625			}
1626			elseif ($pref_refresh_ms)
1627			{
1628				$refresh_ms = $pref_refresh_ms;
1629			}
1630			else
1631			{
1632				// user pref is NOT to refresh AND we were not given another value to use
1633				// LEAVING
1634				return '';
1635			}
1636
1637			/*
1638			// if NOT supplied a "reload_me" URI then we must figure one out
1639			if ($reload_me == '')
1640			{
1641				if ((stristr($GLOBALS['PHP_SELF'], '/email/index.php'))
1642				||  (	((isset($GLOBALS['phpgw']->msg->ref_GET['menuaction']))
1643					&& (stristr($GLOBALS['phpgw']->msg->ref_GET['menuaction'], 'email.uiindex.index')))
1644					)
1645				)
1646				{
1647					if ((isset($GLOBALS['phpgw_info']['flags']['email_refresh_uri']))
1648					&& ($GLOBALS['phpgw_info']['flags']['email_refresh_uri'] != ''))
1649					{
1650						$reload_me = $GLOBALS['phpgw']->link('/index.php',$GLOBALS['phpgw_info']['flags']['email_refresh_uri']);
1651					}
1652					else
1653					{
1654						$reload_me = $GLOBALS['phpgw']->link('/email/index.php');
1655					}
1656				}
1657				elseif (eregi("^.*\/home\.php.*$",$GLOBALS['PHP_SELF']))
1658				{
1659					$reload_me = $GLOBALS['phpgw']->link('/home.php');
1660				}
1661			}
1662			*/
1663
1664			// reality check
1665			$int_refresh_ms = (int)$refresh_ms;
1666			if ($int_refresh_ms < 60000)
1667			{
1668				// less than 1 minute us BS, use a fallback value of 4 minutes
1669				$refresh_ms = 240000;
1670			}
1671
1672			// make the $refresh_ms into a string
1673			$refresh_ms = (string)$refresh_ms;
1674			// now if we have a reload_me URI, then
1675			// make the JS command string if necessary
1676			if (($reload_me != '')
1677			&& ($refresh_ms != ''))
1678			{
1679				$reload_me_full = $GLOBALS['phpgw']->link('/index.php',$reload_me);
1680				// set refresh time in miliseconds  (1000 = 1 sec)  (180000 = 180 sec = 3 minutes)
1681				//  ( 240000 = 240 sec = 4 min)   (300000 = 5 min)   (600000 = 10 min)
1682				//$refresh_ms = '240000';
1683				$reload_js =
1684					 '<script language="javascript">'."\r\n"
1685					.'window.setTimeout('."'".'window.location="'
1686					.$reload_me_full.'"; '."'".','.$refresh_ms.');'."\r\n"
1687					.'</script>'."\r\n";
1688			}
1689			else
1690			{
1691				// we have no URI to reload
1692				$reload_js = '';
1693			}
1694			// returning  $reload_js which may be '' if we did not have enough info
1695			return $reload_js;
1696		}
1697
1698		/**************************************************************************\
1699		*	GENERIC ERROR REPORT
1700		\**************************************************************************/
1701
1702		/*!
1703		@capability GENERIC ERROR REPORT
1704		@discussion This is not really a widget, but this is a good place to put this. In cases such
1705		as a login error, it is not user friendly to output a text only page with an echod out error.
1706		At the very least we should output the template as usual, and insert the error text where
1707		the page content would go. This way the user has all the links and buttons to click on
1708		to get out of the error page.
1709		@author Angles
1710		*/
1711
1712		/*!
1713		@function init_error_report_values
1714		@abstract Initialize error report with default text, please call this first.
1715		@discussion Simple function to initialize the error report with some default text.
1716		I can not imagine how you could use this twice since the actual error report is a full
1717		template page output, BUT still this is how the initial default values are filled. Please
1718		call this first.
1719		@author Angles
1720		*/
1721		function init_error_report_values()
1722		{
1723			$this->F_error_report_text = lang('error text not provided');
1724			$this->F_go_somewhere_link = '';
1725			$go_home_url = $GLOBALS['phpgw']->link('/home.php');
1726			$go_home_text = lang('click here to return to your home page.');
1727			$this->F_go_home_link = '<a href="'.$go_home_url.'">'.$go_home_text.'</a>';
1728		}
1729
1730		/*!
1731		@function prop_error_report_text
1732		@abstract Set or Get the error report text.
1733		@param $error_report_text (string) the error to show the user.
1734		@param $append (boolean) if true, then add to the error text. If false, replace error text.
1735		@discussion It initialized with a generic "not provided" string,
1736		which you change to the real error report text with this function.
1737		It checks for the default generic text, and always replaces it even if append it true.
1738		So this way you can specify append but still never accidently keep the mindless
1739		default error text.
1740		@author Angles
1741		*/
1742		function prop_error_report_text($error_report_text='', $append=False)
1743		{
1744			if ($error_report_text)
1745			{
1746				// ALWAYS make sure to clear the mindless default text before you append
1747				if (($this->F_error_report_text == lang($this->F_mindless_default_txt))
1748				|| ($append == False))
1749				{
1750					$this->F_error_report_text = $error_report_text;
1751				}
1752				else
1753				{
1754					$this->F_error_report_text .= $error_report_text;
1755				}
1756			}
1757			return $this->F_error_report_text;
1758		}
1759
1760		/*!
1761		@function prop_go_somewhere_link
1762		@abstract Set or Get the go somewhere link.
1763		@param $go_somewhere_url (string in url form) a helpful link to show the user.
1764		@param $go_somewhere_text (string in url form) the text for the HREF for this helpful link to show the user.
1765		@discussion This is optional, in any case the "go home link" will be displayed,
1766		But with this function you can additionally show a link to something useful given
1767		the error the user just encountered, perhaps to the preferences page, for example.
1768		The two params are required for this function to make the HREF.
1769		@author Angles
1770		*/
1771		function prop_go_somewhere_link($go_somewhere_url='', $go_somewhere_text='')
1772		{
1773			if (($go_somewhere_url)
1774			&& ($go_somewhere_text))
1775			{
1776				$this->set_href_link($go_somewhere_url);
1777				$this->set_href_clickme($go_somewhere_text);
1778				$this->F_go_somewhere_link = $this->get_href();
1779			}
1780			return $this->F_go_somewhere_link;
1781		}
1782
1783		/*!
1784		@function display_error_report_page
1785		@abstract A complete output of the template with your error report in the content section.
1786		@param $do_exit (boolean) if empty or false, then this function will NOT call common exit,
1787		if filled or True, it will call msg end_request and common EXIT.
1788		@discussion Handles all necessary template parsing, you should set the error text and helpful
1789		href, call this function. Param $do_exit is useful if you are calling this report from within
1790		the msg object itself, then this function will call msg end_request and then the common phpgw exit.
1791		@author Angles
1792		*/
1793		function display_error_report_page($do_exit='')
1794		{
1795			unset($GLOBALS['phpgw_info']['flags']['noheader']);
1796			unset($GLOBALS['phpgw_info']['flags']['nonavbar']);
1797			$GLOBALS['phpgw_info']['flags']['noappheader'] = True;
1798			$GLOBALS['phpgw_info']['flags']['noappfooter'] = True;
1799			$GLOBALS['phpgw']->common->phpgw_header();
1800
1801			$GLOBALS['phpgw']->template->set_file(array(
1802				'T_error_report' => 'error_report.tpl'
1803			));
1804			$GLOBALS['phpgw']->template->set_var('error_report_text', $this->prop_error_report_text());
1805			$GLOBALS['phpgw']->template->set_var('go_somewhere_link', $this->prop_go_somewhere_link());
1806			$GLOBALS['phpgw']->template->set_var('go_home_link', $this->F_go_home_link);
1807			$GLOBALS['phpgw']->template->pfp('out','T_error_report');
1808			// do we exit the script here?
1809			if ($do_exit)
1810			{
1811				// kill this script, we re outa here...
1812				if (is_object($GLOBALS['phpgw']->msg))
1813				{
1814					$GLOBALS['phpgw']->msg->end_request();
1815					$GLOBALS['phpgw']->msg = '';
1816					unset($GLOBALS['phpgw']->msg);
1817				}
1818				$GLOBALS['phpgw']->common->phpgw_exit();
1819			}
1820		}
1821
1822		/*!
1823		@function get_geek_bar
1824		@abstract TESTING goes on bottom of index page
1825		@author Angles
1826		*/
1827		function get_geek_bar()
1828		{
1829			$row_on = $GLOBALS['phpgw_info']['theme']['row_on'];
1830			$this_server_type = $GLOBALS['phpgw']->msg->get_pref_value('mail_server_type');
1831			if (extension_loaded('imap') && function_exists('imap_open'))
1832			{
1833				$library_usage = 'builtin';
1834			}
1835			else
1836			{
1837				$library_usage = 'AM sockets';
1838			}
1839			$anglemail_table_exists = 'installed';
1840			if ($GLOBALS['phpgw']->msg->so->so_am_table_exists() == False)
1841			{
1842				$anglemail_table_exists = 'NOT '.$anglemail_table_exists;
1843			}
1844			$compression = 'NOT available';
1845			//if (function_exists('bzcompress'))
1846			//{
1847			//	$compression = 'bz2';
1848			//}
1849			//else
1850			if (function_exists('gzcompress'))
1851			{
1852				$compression = 'gzip';
1853			}
1854			$spell_available = 'available';
1855			if (function_exists('pspell_check') == False)
1856			{
1857				$spell_available = 'NOT '.$spell_available;
1858			}
1859			if ($GLOBALS['phpgw']->msg->phpgw_before_xslt == True)
1860			{
1861				$using_xslt = 'no';
1862			}
1863			else
1864			{
1865				$using_xslt = 'yes';
1866			}
1867
1868			// did we connect
1869			$accts_connected = '';
1870			// put together a list of all enabled accounts so we will check them for an open stream
1871			for ($i=0; $i < count($GLOBALS['phpgw']->msg->extra_and_default_acounts); $i++)
1872			{
1873				if ($GLOBALS['phpgw']->msg->extra_and_default_acounts[$i]['status'] == 'enabled')
1874				{
1875					$this_acctnum = (int)$GLOBALS['phpgw']->msg->extra_and_default_acounts[$i]['acctnum'];
1876					if (($GLOBALS['phpgw']->msg->get_isset_arg('mailsvr_stream', $this_acctnum) == True)
1877					&& ((string)$GLOBALS['phpgw']->msg->get_arg_value('mailsvr_stream', $this_acctnum) != ''))
1878					{
1879						$accts_connected .= (string)$this_acctnum.',';
1880					}
1881				}
1882			}
1883			// get rid of trailing , if it exists
1884			if (stristr($accts_connected, ','))
1885			{
1886				$accts_connected = substr($accts_connected,0,-1);
1887				$did_connect = 'yes ('.$accts_connected.')';
1888
1889			}
1890			else
1891			{
1892				$did_connect = 'no';
1893			}
1894
1895			$geek_bar =
1896			'<br />
1897			<table border="0" cellpadding="4" cellspacing="0" width="100%" align="center">
1898			<tr bgcolor="'.$row_on.'" class="row_on">
1899				<td width="100%" align="left">'."\r\n"
1900					//.'<small style="font-size: 10pt;">'
1901					.'<small style="font-size: xx-small;">'
1902					.'<font color="brown">GeekBar:</font> '
1903					.'Server Type: ['.$this_server_type.'] -- '
1904					.'IMAP library: ['.$library_usage.'] -- '
1905					.'AngleMail Table: ['.$anglemail_table_exists.'] -- '
1906					.'compression: ['.$compression.'] -- '
1907					.'spelling: ['.$spell_available.'] -- '
1908					.'using XSLT: ['.$using_xslt.'] -- '
1909					.'did connect: ['.$did_connect.'] '
1910					.'</small>'
1911				."\r\n"
1912			.'	</td>
1913			</table>';
1914			return $geek_bar;
1915		}
1916	}
1917?>
1918