thomascube
2006-04-04 f3704e18d89e4065cede8509256d7fbf483b7fe6
commit | author | age
e0ed97 1 /*
4e17e6 2  +-----------------------------------------------------------------------+
T 3  | RoundCube Webmail Client Script                                       |
4  |                                                                       |
5  | This file is part of the RoundCube Webmail client                     |
6  | Copyright (C) 2005, RoundCube Dev, - Switzerland                      |
30233b 7  | Licensed under the GNU GPL                                            |
4e17e6 8  |                                                                       |
T 9  +-----------------------------------------------------------------------+
8c2e58 10  | Authors: Thomas Bruederli <roundcube@gmail.com>                       |
T 11  |          Charles McNulty <charles@charlesmcnulty.com>                 |
4e17e6 12  +-----------------------------------------------------------------------+
15a9d1 13  
T 14   $Id$
4e17e6 15 */
T 16
b11a00 17 // Constants
T 18 var CONTROL_KEY = 1;
19 var SHIFT_KEY = 2;
20 var CONTROL_SHIFT_KEY = 3;
4e17e6 21
T 22 var rcube_webmail_client;
23
24 function rcube_webmail()
25   {
26   this.env = new Object();
10a699 27   this.labels = new Object();
4e17e6 28   this.buttons = new Object();
T 29   this.gui_objects = new Object();
30   this.commands = new Object();
31   this.selection = new Array();
32
33   // create public reference to myself
34   rcube_webmail_client = this;
35   this.ref = 'rcube_webmail_client';
36  
37   // webmail client settings
38   this.dblclick_time = 600;
39   this.message_time = 5000;
e66f5b 40   this.request_timeout = 180000;
ecf759 41   this.kepp_alive_interval = 60000;
4e17e6 42   this.mbox_expression = new RegExp('[^0-9a-z\-_]', 'gi');
T 43   this.env.blank_img = 'skins/default/images/blank.gif';
44   
45   // mimetypes supported by the browser (default settings)
46   this.mimetypes = new Array('text/plain', 'text/html', 'text/xml',
47                              'image/jpeg', 'image/gif', 'image/png',
48                              'application/x-javascript', 'application/pdf',
49                              'application/x-shockwave-flash');
50
51
52   // set environment variable
53   this.set_env = function(name, value)
54     {
55     //if (!this.busy)
56       this.env[name] = value;    
57     };
10a699 58
T 59
60   // add a localized label to the client environment
61   this.add_label = function(key, value)
62     {
63     this.labels[key] = value;
64     };
65
4e17e6 66
T 67   // add a button to the button list
68   this.register_button = function(command, id, type, act, sel, over)
69     {
70     if (!this.buttons[command])
71       this.buttons[command] = new Array();
72       
73     var button_prop = {id:id, type:type};
74     if (act) button_prop.act = act;
75     if (sel) button_prop.sel = sel;
76     if (over) button_prop.over = over;
77
78     this.buttons[command][this.buttons[command].length] = button_prop;    
79     };
80
81
82   // register a specific gui object
83   this.gui_object = function(name, id)
84     {
85     this.gui_objects[name] = id;
86     };
87
88
89   // initialize webmail client
90   this.init = function()
91     {
92     this.task = this.env.task;
93     
94     // check browser
a95e0e 95     if (!bw.dom || !bw.xmlhttp_test())
4e17e6 96       {
T 97       location.href = this.env.comm_path+'&_action=error&_code=0x199';
98       return;
99       }
100     
101     // find all registered gui objects
102     for (var n in this.gui_objects)
103       this.gui_objects[n] = rcube_find_object(this.gui_objects[n]);
104       
105     // tell parent window that this frame is loaded
106     if (this.env.framed && parent.rcmail && parent.rcmail.set_busy)
107       parent.rcmail.set_busy(false);
108
109     // enable general commands
110     this.enable_command('logout', 'mail', 'addressbook', 'settings', true);
111     
112     switch (this.task)
113       {
114       case 'mail':
d58c69 115         var msg_list_frame = this.gui_objects.mailcontframe;
4e17e6 116         var msg_list = this.gui_objects.messagelist;
T 117         if (msg_list)
118           {
d58c69 119           msg_list_frame.onmousedown = function(e){return rcube_webmail_client.click_on_list(e);};
4e17e6 120           this.init_messagelist(msg_list);
T 121           this.enable_command('markread', true);
122           }
123
124         // enable mail commands
4647e1 125         this.enable_command('list', 'compose', 'add-contact', 'search', 'reset-search', true);
4e17e6 126         
T 127         if (this.env.action=='show')
128           {
583f1c 129           this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', 'viewsource', 'print', 'load-attachment', true);
4e17e6 130           if (this.env.next_uid)
T 131             this.enable_command('nextmessage', true);
132           if (this.env.prev_uid)
133             this.enable_command('previousmessage', true);
134           }
135
136         if (this.env.action=='show' && this.env.blockedobjects)
137           {
138           if (this.gui_objects.remoteobjectsmsg)
139             this.gui_objects.remoteobjectsmsg.style.display = 'block';
140           this.enable_command('load-images', true);
141           }  
142
143         if (this.env.action=='compose')
144           this.enable_command('add-attachment', 'send-attachment', 'send', true);
145           
146         if (this.env.messagecount)
15a9d1 147           this.enable_command('select-all', 'select-none', 'sort', 'expunge', true);
4e17e6 148
5e3512 149         if (this.env.messagecount && this.env.mailbox==this.env.trash_mailbox)
T 150           this.enable_command('purge', true);
151
4e17e6 152         this.set_page_buttons();
T 153
154         // focus this window
155         window.focus();
156
157         // init message compose form
158         if (this.env.action=='compose')
159           this.init_messageform();
160
161         // show printing dialog
162         if (this.env.action=='print')
163           window.print();
15a9d1 164           
T 165         // get unread count for each mailbox
166         if (this.gui_objects.mailboxlist)
167           this.http_request('getunread', '');
4e17e6 168
T 169         break;
170
171
172       case 'addressbook':
d1d2c4 173         var contacts_list      = this.gui_objects.contactslist;
S 174         var ldap_contacts_list = this.gui_objects.ldapcontactslist;
175
4e17e6 176         if (contacts_list)
T 177           this.init_contactslist(contacts_list);
178       
d1d2c4 179         if (ldap_contacts_list)
S 180           this.init_ldapsearchlist(ldap_contacts_list);
181
4e17e6 182         this.set_page_buttons();
T 183           
184         if (this.env.cid)
185           this.enable_command('show', 'edit', true);
186
187         if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform)
188           this.enable_command('save', true);
189       
c0da98 190         this.enable_command('list', 'add', true);
S 191
192         this.enable_command('ldappublicsearch', this.env.ldappublicsearch);
193
4e17e6 194         break;
T 195
196
197       case 'settings':
198         this.enable_command('preferences', 'identities', 'save', 'folders', true);
199         
200         if (this.env.action=='identities' || this.env.action=='edit-identity' || this.env.action=='add-identity')
201           this.enable_command('edit', 'add', 'delete', true);
202
203         if (this.env.action=='edit-identity' || this.env.action=='add-identity')
204           this.enable_command('save', true);
205           
206         if (this.env.action=='folders')
207           this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'delete-folder', true);
208           
209         var identities_list = this.gui_objects.identitieslist;
210         if (identities_list)
211           this.init_identitieslist(identities_list);
212
213         break;
214
215       case 'login':
216         var input_user = rcube_find_object('_user');
217         var input_pass = rcube_find_object('_pass');
218         if (input_user && input_user.value=='')
219           input_user.focus();
220         else if (input_pass)
221           input_pass.focus();
222           
223         this.enable_command('login', true);
224         break;
225       
226       default:
227         break;
228       }
229
230
231     // enable basic commands
232     this.enable_command('logout', true);
233
234     // disable browser's contextmenus
8c2e58 235     // document.oncontextmenu = function(){ return false; }
4e17e6 236
d58c69 237     // load body click event
S 238     document.onmousedown = function(){ return rcube_webmail_client.reset_click(); };
239     document.onkeydown   = function(e){ return rcube_webmail_client.use_arrow_keys(e, msg_list_frame); };
240
241     
4e17e6 242     // flag object as complete
T 243     this.loaded = true;
7902df 244           
4e17e6 245     // show message
T 246     if (this.pending_message)
247       this.display_message(this.pending_message[0], this.pending_message[1]);
ecf759 248       
15a9d1 249     // start interval for keep-alive/recent_check signal
3f9edb 250     if (this.kepp_alive_interval && this.task=='mail' && this.gui_objects.messagelist)
T 251       this.kepp_alive_int = setInterval(this.ref+'.check_for_recent()', this.kepp_alive_interval);
8c2e58 252     else if (this.task!='login')
3f9edb 253       this.kepp_alive_int = setInterval(this.ref+'.send_keep_alive()', this.kepp_alive_interval);
4e17e6 254     };
T 255
d58c69 256   // reset last clicked if user clicks on anything other than the message table
S 257   this.reset_click = function()
258     {
259     this.in_message_list = false;
260     };
261     
262   this.click_on_list = function(e)
263     {
264     if (!e)
265       e = window.event;
266
267     this.in_message_list = true;
268     e.cancelBubble = true;
269     };
270
271   // reset last clicked if user clicks on anything other than the message table
272   this.use_arrow_keys = function(e, msg_list_frame) {
273     if (this.in_message_list != true) 
274       return true;
275
276     var keyCode = document.layers ? e.which : document.all ? event.keyCode : document.getElementById ? e.keyCode : 0;
277     var mod_key = this.get_modifier(e);
278     var scroll_to = 0;
8c2e58 279     
d58c69 280     var last_selected_row = this.list_rows[this.last_selected];
S 281
282     if (keyCode == 40) { // down arrow key pressed
283       var new_row = last_selected_row.obj.nextSibling;
284       while (new_row && new_row.nodeType != 1) {
285         new_row = new_row.nextSibling;
286       }
287       if (!new_row) return false;
288       scroll_to = (Number(new_row.offsetTop) + Number(new_row.offsetHeight)) - Number(msg_list_frame.offsetHeight);
289     } else if (keyCode == 38) { // up arrow key pressed
290       var new_row = last_selected_row.obj.previousSibling;
291       while (new_row && new_row.nodeType != 1) {
292         new_row = new_row.previousSibling;
293       }
294       if (!new_row) return false;
295       scroll_to = new_row.offsetTop;
f108b9 296     } else {return true;}
d58c69 297     
S 298     if (mod_key != CONTROL_KEY)
299       this.select_row(new_row.uid,mod_key);
300
301     if (((Number(new_row.offsetTop)) < (Number(msg_list_frame.scrollTop))) || 
302        ((Number(new_row.offsetTop) + Number(new_row.offsetHeight)) > (Number(msg_list_frame.scrollTop) + Number(msg_list_frame.offsetHeight)))) {
303       msg_list_frame.scrollTop = scroll_to;
304     }
305
306     return false;
307   };
4e17e6 308
T 309   // get all message rows from HTML table and init each row
310   this.init_messagelist = function(msg_list)
311     {
312     if (msg_list && msg_list.tBodies[0])
313       {
d58c69 314           
4e17e6 315       this.message_rows = new Array();
T 316
317       var row;
318       for(var r=0; r<msg_list.tBodies[0].childNodes.length; r++)
319         {
320         row = msg_list.tBodies[0].childNodes[r];
321         //row = msg_list.tBodies[0].rows[r];
322         this.init_message_row(row);
323         }
324       }
325       
326     // alias to common rows array
327     this.list_rows = this.message_rows;
328     };
329     
330     
331   // make references in internal array and set event handlers
332   this.init_message_row = function(row)
333     {
334     var uid, msg_icon;
335     
336     if (String(row.id).match(/rcmrow([0-9]+)/))
337       {
338       uid = RegExp.$1;
339       row.uid = uid;
340               
341       this.message_rows[uid] = {id:row.id, obj:row,
342                                 classname:row.className,
343                                 unread:this.env.messages[uid] ? this.env.messages[uid].unread : null,
344                                 replied:this.env.messages[uid] ? this.env.messages[uid].replied : null};
345               
346       // set eventhandlers to table row
347       row.onmousedown = function(e){ return rcube_webmail_client.drag_row(e, this.uid); };
348       row.onmouseup = function(e){ return rcube_webmail_client.click_row(e, this.uid); };
d58c69 349
b11a00 350       if (document.all)
T 351         row.onselectstart = function() { return false; };
352
4e17e6 353       // set eventhandler to message icon
T 354       if ((msg_icon = row.cells[0].childNodes[0]) && row.cells[0].childNodes[0].nodeName=='IMG')
355         {                
356         msg_icon.id = 'msgicn_'+uid;
357         msg_icon._row = row;
358         msg_icon.onmousedown = function(e) { rcube_webmail_client.command('markread', this); };
359                 
360         // get message icon and save original icon src
361         this.message_rows[uid].icon = msg_icon;
362         }
363       }
364     };
365
366
367   // init message compose form: set focus and eventhandlers
368   this.init_messageform = function()
369     {
370     if (!this.gui_objects.messageform)
371       return false;
372     
373     //this.messageform = this.gui_objects.messageform;
1cded8 374     var input_from = rcube_find_object('_from');
4e17e6 375     var input_to = rcube_find_object('_to');
T 376     var input_cc = rcube_find_object('_cc');
377     var input_bcc = rcube_find_object('_bcc');
378     var input_replyto = rcube_find_object('_replyto');
379     var input_subject = rcube_find_object('_subject');
380     var input_message = rcube_find_object('_message');
381     
382     // init live search events
383     if (input_to)
384       this.init_address_input_events(input_to);
385     if (input_cc)
386       this.init_address_input_events(input_cc);
387     if (input_bcc)
388       this.init_address_input_events(input_bcc);
1cded8 389       
T 390     // add signature according to selected identity
391     if (input_from && input_from.type=='select-one')
392       this.change_identity(input_from);
4e17e6 393
T 394     if (input_to && input_to.value=='')
395       input_to.focus();
396     else if (input_subject && input_subject.value=='')
397       input_subject.focus();
398     else if (input_message)
399       this.set_caret2start(input_message); // input_message.focus();
977a29 400     
T 401     // get summary of all field values
402     this.cmp_hash = this.compose_field_hash();
4e17e6 403     };
T 404
405
406   this.init_address_input_events = function(obj)
407     {
408     var handler = function(e){ return rcube_webmail_client.ksearch_keypress(e,this); };
409     var handler2 = function(e){ return rcube_webmail_client.ksearch_blur(e,this); };
410     
411     if (bw.safari)
412       {
413       obj.addEventListener('keydown', handler, false);
414       // obj.addEventListener('blur', handler2, false);
415       }
416     else if (bw.mz)
417       {
418       obj.addEventListener('keypress', handler, false);
419       obj.addEventListener('blur', handler2, false);
420       }
421     else if (bw.ie)
422       {
423       obj.onkeydown = handler;
424       //obj.attachEvent('onkeydown', handler);
425       // obj.attachEvent('onblur', handler2, false);
426       }
427     
428     obj.setAttribute('autocomplete', 'off');       
429     };
430
431
432
433   // get all contact rows from HTML table and init each row
434   this.init_contactslist = function(contacts_list)
435     {
436     if (contacts_list && contacts_list.tBodies[0])
437       {
438       this.contact_rows = new Array();
439
440       var row;
441       for(var r=0; r<contacts_list.tBodies[0].childNodes.length; r++)
442         {
443         row = contacts_list.tBodies[0].childNodes[r];
444         this.init_table_row(row, 'contact_rows');
445         }
446       }
447
448     // alias to common rows array
449     this.list_rows = this.contact_rows;
450     
451     if (this.env.cid)
2a1e18 452       this.highlight_row(this.env.cid);
4e17e6 453     };
T 454
455
d1d2c4 456   // get all contact rows from HTML table and init each row
S 457   this.init_ldapsearchlist = function(ldap_contacts_list)
458     {
459     if (ldap_contacts_list && ldap_contacts_list.tBodies[0])
460       {
461       this.ldap_contact_rows = new Array();
462
463       var row;
464       for(var r=0; r<ldap_contacts_list.tBodies[0].childNodes.length; r++)
465         {
466         row = ldap_contacts_list.tBodies[0].childNodes[r];
467         this.init_table_row(row, 'ldap_contact_rows');
468         }
469       }
470
471     // alias to common rows array
472     this.list_rows = this.ldap_contact_rows;
473     };
474
475
4e17e6 476   // make references in internal array and set event handlers
T 477   this.init_table_row = function(row, array_name)
478     {
479     var cid;
480     
481     if (String(row.id).match(/rcmrow([0-9]+)/))
482       {
483       cid = RegExp.$1;
484       row.cid = cid;
485
486       this[array_name][cid] = {id:row.id,
487                                obj:row,
488                                classname:row.className};
489
490       // set eventhandlers to table row
491       row.onmousedown = function(e) { rcube_webmail_client.in_selection_before=this.cid; return false; };  // fake for drag handler
492       row.onmouseup = function(e){ return rcube_webmail_client.click_row(e, this.cid); };
493       }
494     };
495
496
497   // get all contact rows from HTML table and init each row
498   this.init_identitieslist = function(identities_list)
499     {
500     if (identities_list && identities_list.tBodies[0])
501       {
502       this.identity_rows = new Array();
503
504       var row;
505       for(var r=0; r<identities_list.tBodies[0].childNodes.length; r++)
506         {
507         row = identities_list.tBodies[0].childNodes[r];
508         this.init_table_row(row, 'identity_rows');
509         }
510       }
511
512     // alias to common rows array
513     this.list_rows = this.identity_rows;
514     
515     if (this.env.iid)
2a1e18 516       this.highlight_row(this.env.iid);    
4e17e6 517     };
T 518     
519
520
521   /*********************************************************/
522   /*********       client command interface        *********/
523   /*********************************************************/
524
525
526   // execute a specific command on the web client
527   this.command = function(command, props, obj)
528     {
529     if (obj && obj.blur)
530       obj.blur();
531
532     if (this.busy)
533       return false;
534
535     // command not supported or allowed
536     if (!this.commands[command])
537       {
538       // pass command to parent window
539       if (this.env.framed && parent.rcmail && parent.rcmail.command)
540         parent.rcmail.command(command, props);
541
542       return false;
543       }
15a9d1 544       
T 545       
546    // check input before leaving compose step
547    if (this.task=='mail' && this.env.action=='compose' && (command=='list' || command=='mail' || command=='addressbook' || command=='settings'))
548      {
549      if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning')))
550         return false;
551      }
552
4e17e6 553
T 554     // process command
555     switch (command)
556       {
557       case 'login':
558         if (this.gui_objects.loginform)
559           this.gui_objects.loginform.submit();
560         break;
561
562       case 'logout':
563         location.href = this.env.comm_path+'&_action=logout';
564         break;      
565
566       // commands to switch task
567       case 'mail':
568       case 'addressbook':
569       case 'settings':
570         this.switch_task(command);
571         break;
572
573
574       // misc list commands
575       case 'list':
576         if (this.task=='mail')
4647e1 577           {
ac6b87 578           if (this.env.search_request<0 || (this.env.search_request && props != this.env.mailbox))
4647e1 579             this.reset_qsearch();
4e17e6 580           this.list_mailbox(props);
4647e1 581           }
4e17e6 582         else if (this.task=='addressbook')
T 583           this.list_contacts();
f3b659 584         break;
T 585
586       case 'sort':
587         // get the type of sorting
b076a4 588         var a_sort = props.split('_');
T 589         var sort_col = a_sort[0];
1cded8 590         var sort_order = a_sort[1] ? a_sort[1].toUpperCase() : null;
b076a4 591         var header;
1cded8 592         
T 593         // no sort order specified: toggle
594         if (sort_order==null)
595           {
596           if (this.env.sort_col==sort_col)
597             sort_order = this.env.sort_order=='ASC' ? 'DESC' : 'ASC';
598           else
599             sort_order = this.env.sort_order;
600           }
b076a4 601         
T 602         if (this.env.sort_col==sort_col && this.env.sort_order==sort_order)
603           break;
604
605         // set table header class
606         if (header = document.getElementById('rcmHead'+this.env.sort_col))
607           this.set_classname(header, 'sorted'+(this.env.sort_order.toUpperCase()), false);
608         if (header = document.getElementById('rcmHead'+sort_col))
609           this.set_classname(header, 'sorted'+sort_order, true);
610
611         // save new sort properties
612         this.env.sort_col = sort_col;
613         this.env.sort_order = sort_order;
614
615         // reload message list
1cded8 616         this.list_mailbox('', '', sort_col+'_'+sort_order);
4e17e6 617         break;
T 618
619       case 'nextpage':
620         this.list_page('next');
621         break;
622
623       case 'previouspage':
624         this.list_page('prev');
15a9d1 625         break;
T 626
627       case 'expunge':
628         if (this.env.messagecount)
629           this.expunge_mailbox(this.env.mailbox);
630         break;
631
5e3512 632       case 'purge':
T 633       case 'empty-mailbox':
634         if (this.env.messagecount)
635           this.purge_mailbox(this.env.mailbox);
4e17e6 636         break;
T 637
638
639       // common commands used in multiple tasks
640       case 'show':
641         if (this.task=='mail')
642           {
643           var uid = this.get_single_uid();
644           if (uid && (!this.env.uid || uid != this.env.uid))
645             this.show_message(uid);
646           }
647         else if (this.task=='addressbook')
648           {
649           var cid = props ? props : this.get_single_cid();
650           if (cid && !(this.env.action=='show' && cid==this.env.cid))
651             this.load_contact(cid, 'show');
652           }
653         break;
654
655       case 'add':
656         if (this.task=='addressbook')
d1d2c4 657           if (!window.frames[this.env.contentframe].rcmail)
S 658             this.load_contact(0, 'add');
659           else
660             {
661             if (window.frames[this.env.contentframe].rcmail.selection.length)
662               this.add_ldap_contacts();
663             else
664               this.load_contact(0, 'add');
665             }
4e17e6 666         else if (this.task=='settings')
T 667           {
668           this.clear_selection();
669           this.load_identity(0, 'add-identity');
670           }
671         break;
672
673       case 'edit':
674         var cid;
675         if (this.task=='addressbook' && (cid = this.get_single_cid()))
676           this.load_contact(cid, 'edit');
677         else if (this.task=='settings' && props)
678           this.load_identity(props, 'edit-identity');
679         break;
680
681       case 'save-identity':
682       case 'save':
683         if (this.gui_objects.editform)
10a699 684           {
T 685           var input_pagesize = rcube_find_object('_pagesize');
686           var input_name  = rcube_find_object('_name');
687           var input_email = rcube_find_object('_email');
688
689           // user prefs
e66f5b 690           if (input_pagesize && isNaN(input_pagesize.value))
10a699 691             {
T 692             alert(this.get_label('nopagesizewarning'));
693             input_pagesize.focus();
694             break;
695             }
696           // contacts/identities
697           else
698             {
699             if (input_name && input_name.value == '')
700               {
701               alert(this.get_label('nonamewarning'));
702               input_name.focus();
703               break;
704               }
705             else if (input_email && !rcube_check_email(input_email.value))
706               {
707               alert(this.get_label('noemailwarning'));
708               input_email.focus();
709               break;
710               }
711             }
712
4e17e6 713           this.gui_objects.editform.submit();
10a699 714           }
4e17e6 715         break;
T 716
717       case 'delete':
718         // mail task
719         if (this.task=='mail' && this.env.trash_mailbox && String(this.env.mailbox).toLowerCase()!=String(this.env.trash_mailbox).toLowerCase())
720           this.move_messages(this.env.trash_mailbox);
721         else if (this.task=='mail')
722           this.delete_messages();
723         // addressbook task
724         else if (this.task=='addressbook')
725           this.delete_contacts();
726         // user settings task
727         else if (this.task=='settings')
728           this.delete_identity();
729         break;
730
731
732       // mail task commands
733       case 'move':
734       case 'moveto':
735         this.move_messages(props);
736         break;
737         
738       case 'markread':
739         if (props && !props._row)
740           break;
741         
742         var uid;
743         var flag = 'read';
744         
745         if (props._row.uid)
746           {
747           uid = props._row.uid;
748           this.dont_select = true;
749           
750           // toggle read/unread
751           if (!this.message_rows[uid].unread)
752             flag = 'unread';
753           }
754           
755         this.mark_message(flag, uid);
756         break;
757         
758       case 'load-images':
759         if (this.env.uid)
760           this.show_message(this.env.uid, true);
761         break;
762
763       case 'load-attachment':
764         var url = this.env.comm_path+'&_action=get&_mbox='+this.env.mailbox+'&_uid='+this.env.uid+'&_part='+props.part;
765         
766         // open attachment in frame if it's of a supported mimetype
767         if (this.env.uid && props.mimetype && find_in_array(props.mimetype, this.mimetypes)>=0)
768           {
769           this.attachment_win = window.open(url+'&_frame=1', 'rcubemailattachment');
770           if (this.attachment_win)
771             {
772             setTimeout(this.ref+'.attachment_win.focus()', 10);
773             break;
774             }
775           }
776
777         location.href = url;
778         break;
779         
780       case 'select-all':
781         this.select_all(props);
782         break;
783
784       case 'select-none':
785         this.clear_selection();
786         break;
787
788       case 'nextmessage':
789         if (this.env.next_uid)
09941e 790           this.show_message(this.env.next_uid);
T 791           //location.href = this.env.comm_path+'&_action=show&_uid='+this.env.next_uid+'&_mbox='+this.env.mailbox;
4e17e6 792         break;
T 793
794       case 'previousmessage':
795         if (this.env.prev_uid)
09941e 796           this.show_message(this.env.prev_uid);
T 797           //location.href = this.env.comm_path+'&_action=show&_uid='+this.env.prev_uid+'&_mbox='+this.env.mailbox;
4e17e6 798         break;
d1d2c4 799       
S 800       
4e17e6 801       case 'compose':
T 802         var url = this.env.comm_path+'&_action=compose';
803         
804         // modify url if we're in addressbook
805         if (this.task=='addressbook')
806           {
807           url = this.get_task_url('mail', url);            
808           var a_cids = new Array();
809           
810           // use contact_id passed as command parameter
811           if (props)
812             a_cids[a_cids.length] = props;
813             
814           // get selected contacts
815           else
816             {
d1d2c4 817             if (!window.frames[this.env.contentframe].rcmail.selection.length)
S 818               {
819               for (var n=0; n<this.selection.length; n++)
820                 a_cids[a_cids.length] = this.selection[n];
821               }
822             else
823               {
824               var frameRcmail = window.frames[this.env.contentframe].rcmail;
825               // get the email address(es)
826               for (var n=0; n<frameRcmail.selection.length; n++)
827                 a_cids[a_cids.length] = frameRcmail.ldap_contact_rows[frameRcmail.selection[n]].obj.cells[1].innerHTML;
828               }
4e17e6 829             }
T 830           if (a_cids.length)
831             url += '&_to='+a_cids.join(',');
832           else
833             break;
d1d2c4 834             
4e17e6 835           }
T 836         else if (props)
837            url += '&_to='+props;
d1d2c4 838         
S 839         // don't know if this is necessary...
840         url = url.replace(/&_framed=1/, "");
4e17e6 841
T 842         this.set_busy(true);
d1d2c4 843
S 844         // need parent in case we are coming from the contact frame
845         parent.window.location.href = url;
846         break;    
4e17e6 847
T 848       case 'send':
849         if (!this.gui_objects.messageform)
850           break;
851           
977a29 852         if (!this.check_compose_input())
10a699 853           break;
T 854
855         // all checks passed, send message
856         this.set_busy(true, 'sendingmessage');
857         var form = this.gui_objects.messageform;
858         form.submit();
4e17e6 859         break;
T 860
861       case 'add-attachment':
862         this.show_attachment_form(true);
863         
864       case 'send-attachment':
865         this.upload_file(props)      
866         break;
867
583f1c 868       case 'reply-all':
4e17e6 869       case 'reply':
T 870         var uid;
871         if (uid = this.get_single_uid())
872           {
873           this.set_busy(true);
583f1c 874           location.href = this.env.comm_path+'&_action=compose&_reply_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : '');
4e17e6 875           }
T 876         break;      
877
878       case 'forward':
879         var uid;
880         if (uid = this.get_single_uid())
881           {
882           this.set_busy(true);
883           location.href = this.env.comm_path+'&_action=compose&_forward_uid='+uid+'&_mbox='+escape(this.env.mailbox);
884           }
885         break;
886         
887       case 'print':
888         var uid;
889         if (uid = this.get_single_uid())
890           {
891           this.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+escape(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''));
892           if (this.printwin)
893             setTimeout(this.ref+'.printwin.focus()', 20);
894           }
895         break;
896
897       case 'viewsource':
898         var uid;
899         if (uid = this.get_single_uid())
900           {          
901           this.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+this.env.uid+'&_mbox='+escape(this.env.mailbox));
902           if (this.sourcewin)
903             setTimeout(this.ref+'.sourcewin.focus()', 20);
904           }
905         break;
906
907       case 'add-contact':
908         this.add_contact(props);
909         break;
d1d2c4 910       
4647e1 911       // mail quicksearch
T 912       case 'search':
913         if (!props && this.gui_objects.qsearchbox)
914           props = this.gui_objects.qsearchbox.value;
915         if (props)
916           this.qsearch(escape(props), this.env.mailbox);
917         break;
918
919       // reset quicksearch        
920       case 'reset-search':
921         var s = this.env.search_request;
922         this.reset_qsearch();
923         
924         if (s)
925           this.list_mailbox(this.env.mailbox);
926         break;
d1d2c4 927
S 928       // ldap search
929       case 'ldappublicsearch':
930         if (this.gui_objects.ldappublicsearchform) 
931           this.gui_objects.ldappublicsearchform.submit();
932         else 
933           this.ldappublicsearch(command);
934         break; 
4e17e6 935
T 936
937       // user settings commands
938       case 'preferences':
939         location.href = this.env.comm_path;
940         break;
941
942       case 'identities':
943         location.href = this.env.comm_path+'&_action=identities';
944         break;
945           
946       case 'delete-identity':
947         this.delete_identity();
948         
949       case 'folders':
950         location.href = this.env.comm_path+'&_action=folders';
951         break;
952
953       case 'subscribe':
954         this.subscribe_folder(props);
955         break;
956
957       case 'unsubscribe':
958         this.unsubscribe_folder(props);
959         break;
960         
961       case 'create-folder':
962         this.create_folder(props);
963         break;
964
965       case 'delete-folder':
1cded8 966         if (confirm(this.get_label('deletefolderconfirm')))
4e17e6 967           this.delete_folder(props);
T 968         break;
969
970       }
971
972     return obj ? false : true;
973     };
974
975
976   // set command enabled or disabled
977   this.enable_command = function()
978     {
979     var args = this.enable_command.arguments;
980     if(!args.length) return -1;
981
982     var command;
983     var enable = args[args.length-1];
984     
985     for(var n=0; n<args.length-1; n++)
986       {
987       command = args[n];
988       this.commands[command] = enable;
989       this.set_button(command, (enable ? 'act' : 'pas'));
990       }
991     };
992
993
a95e0e 994   // lock/unlock interface
4e17e6 995   this.set_busy = function(a, message)
T 996     {
997     if (a && message)
10a699 998       {
T 999       var msg = this.get_label(message);
1000       if (msg==message)        
1001         msg = 'Loading...';
1002
1003       this.display_message(msg, 'loading', true);
1004       }
4e17e6 1005     else if (!a && this.busy)
T 1006       this.hide_message();
1007
1008     this.busy = a;
1009     //document.body.style.cursor = a ? 'wait' : 'default';
1010     
1011     if (this.gui_objects.editform)
1012       this.lock_form(this.gui_objects.editform, a);
a95e0e 1013       
T 1014     // clear pending timer
1015     if (this.request_timer)
1016       clearTimeout(this.request_timer);
1017
1018     // set timer for requests
1019     if (a && this.request_timeout)
1020       this.request_timer = setTimeout(this.ref+'.request_timed_out()', this.request_timeout);
4e17e6 1021     };
T 1022
1023
10a699 1024   // return a localized string
T 1025   this.get_label = function(name)
1026     {
1027     if (this.labels[name])
1028       return this.labels[name];
1029     else
1030       return name;
1031     };
1032
1033
1034   // switch to another application task
4e17e6 1035   this.switch_task = function(task)
T 1036     {
01bb03 1037     if (this.task===task && task!='mail')
4e17e6 1038       return;
T 1039
01bb03 1040     var url = this.get_task_url(task);
T 1041     if (task=='mail')
1042       url += '&_mbox=INBOX';
1043
4e17e6 1044     this.set_busy(true);
01bb03 1045     location.href = url;
4e17e6 1046     };
T 1047
1048
1049   this.get_task_url = function(task, url)
1050     {
1051     if (!url)
1052       url = this.env.comm_path;
1053
1054     return url.replace(/_task=[a-z]+/, '_task='+task);
a95e0e 1055     };
T 1056     
1057   
1058   // called when a request timed out
1059   this.request_timed_out = function()
1060     {
1061     this.set_busy(false);
1062     this.display_message('Request timed out!', 'error');
4e17e6 1063     };
T 1064
1065
1066   /*********************************************************/
1067   /*********        event handling methods         *********/
1068   /*********************************************************/
1069
1070
1071   // onmouseup handler for mailboxlist item
1072   this.mbox_mouse_up = function(mbox)
1073     {
1074     if (this.drag_active)
1075       this.command('moveto', mbox);
1076     else
1077       this.command('list', mbox);
1078       
1079     return false;
1080     };
1081
1082
1083   // onmousedown-handler of message list row
1084   this.drag_row = function(e, id)
1085     {
1086     this.in_selection_before = this.in_selection(id) ? id : false;
1087
1088     // don't do anything (another action processed before)
1089     if (this.dont_select)
1090       return false;
1091
b11a00 1092     // selects currently unselected row
4e17e6 1093     if (!this.in_selection_before)
b11a00 1094     {
d58c69 1095       var mod_key = this.get_modifier(e);
S 1096       this.select_row(id,mod_key);
b11a00 1097     }
4e17e6 1098     
T 1099     if (this.selection.length)
1100       {
1101       this.drag_start = true;
1102       document.onmousemove = function(e){ return rcube_webmail_client.drag_mouse_move(e); };
1103       document.onmouseup = function(e){ return rcube_webmail_client.drag_mouse_up(e); };
1104       }
1105
1106     return false;
1107     };
1108
1109
1110   // onmouseup-handler of message list row
1111   this.click_row = function(e, id)
1112     {
8c2e58 1113     var mod_key = this.get_modifier(e);
d58c69 1114
4e17e6 1115     // don't do anything (another action processed before)
T 1116     if (this.dont_select)
1117       {
1118       this.dont_select = false;
1119       return false;
1120       }
1121     
b11a00 1122     // unselects currently selected row    
8c2e58 1123     if (!this.drag_active && this.in_selection_before==id)
d58c69 1124       this.select_row(id,mod_key);
8c2e58 1125
4e17e6 1126     this.drag_start = false;
T 1127     this.in_selection_before = false;
1128         
1129     // row was double clicked
8c2e58 1130     if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked && !mod_key)
4e17e6 1131       {
T 1132       this.show_message(id);
1133       return false;
1134       }
1135     else if (this.task=='addressbook')
1136       {
d1d2c4 1137       if (this.contact_rows && this.selection.length==1)
S 1138         {
4e17e6 1139         this.load_contact(this.selection[0], 'show', true);
d1d2c4 1140         // change the text for the add contact button
S 1141         var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
1142         for (i = 0; i < links.length; i++)
1143           {
1144           var onclickstring = new String(links[i].onclick);
1145           if (onclickstring.search('\"add\"') != -1)
1146             links[i].title = this.env.newcontact;
1147           }
1148         }
1149       else if (this.contact_rows && this.contact_rows[id].clicked)
4e17e6 1150         {
T 1151         this.load_contact(id, 'show');
1152         return false;
1153         }
d1d2c4 1154       else if (this.ldap_contact_rows && !this.ldap_contact_rows[id].clicked)
S 1155         {
1156         // clear selection
1157         parent.rcmail.clear_selection();
1158
1159         // disable delete
1160         parent.rcmail.set_button('delete', 'pas');
1161
1162         // change the text for the add contact button
1163         var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
1164         for (i = 0; i < links.length; i++)
1165           {
1166           var onclickstring = new String(links[i].onclick);
1167           if (onclickstring.search('\"add\"') != -1)
1168             links[i].title = this.env.addcontact;
1169           }
1170         }
1171       // handle double click event
1172       else if (this.ldap_contact_rows && this.selection.length==1 && this.ldap_contact_rows[id].clicked)
1173         this.command('compose', this.ldap_contact_rows[id].obj.cells[1].innerHTML);
4e17e6 1174       else if (this.env.contentframe)
T 1175         {
1176         var elm = document.getElementById(this.env.contentframe);
1177         elm.style.visibility = 'hidden';
1178         }
1179       }
1180     else if (this.task=='settings')
1181       {
1182       if (this.selection.length==1)
1183         this.command('edit', this.selection[0]);
1184       }
1185
1186     this.list_rows[id].clicked = true;
1187     setTimeout(this.ref+'.list_rows['+id+'].clicked=false;', this.dblclick_time);
1188       
1189     return false;
1190     };
1191
1192
1193
1194   /*********************************************************/
1195   /*********     (message) list functionality      *********/
1196   /*********************************************************/
1197
d58c69 1198   // highlight/unhighlight a row
S 1199   this.highlight_row = function(id, multiple)
4e17e6 1200     {
T 1201     var selected = false
1202     
1203     if (this.list_rows[id] && !multiple)
1204       {
1205       this.clear_selection();
1206       this.selection[0] = id;
1207       this.list_rows[id].obj.className += ' selected';
1208       selected = true;
1209       }
1210     
1211     else if (this.list_rows[id])
1212       {
1213       if (!this.in_selection(id))  // select row
1214         {
1215         this.selection[this.selection.length] = id;
1216         this.set_classname(this.list_rows[id].obj, 'selected', true);        
1217         }
1218       else  // unselect row
1219         {
1220         var p = find_in_array(id, this.selection);
1221         var a_pre = this.selection.slice(0, p);
1222         var a_post = this.selection.slice(p+1, this.selection.length);
1223         this.selection = a_pre.concat(a_post);
1224         this.set_classname(this.list_rows[id].obj, 'selected', false);
1225         }
1226       selected = (this.selection.length==1);
1227       }
1228
1229     // enable/disable commands for message
1230     if (this.task=='mail')
1231       {
583f1c 1232       this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', selected);
4e17e6 1233       this.enable_command('delete', 'moveto', this.selection.length>0 ? true : false);
T 1234       }
1235     else if (this.task=='addressbook')
1236       {
1237       this.enable_command('edit', /*'print',*/ selected);
1238       this.enable_command('delete', 'compose', this.selection.length>0 ? true : false);
1239       }
1240     };
1241
b11a00 1242
d58c69 1243 // selects or unselects the proper row depending on the modifier key pressed
S 1244   this.select_row = function(id,mod_key)  { 
1245       if (!mod_key) {
1246       this.shift_start = id;
1247         this.highlight_row(id, false);
1248     } else {
1249       switch (mod_key) {
1250         case SHIFT_KEY: { 
1251           this.shift_select(id,false); 
1252           break; }
1253         case CONTROL_KEY: { 
1254           this.shift_start = id;
1255           this.highlight_row(id, true); 
1256           break; 
1257           }
1258         case CONTROL_SHIFT_KEY: { 
1259           this.shift_select(id,true);
1260           break;
1261           }
1262         default: {
1263           this.highlight_row(id, false); 
1264           break;
1265           }
1266       }
1267     }
1268     this.last_selected = id;
1269   };
1270
1271   this.shift_select = function(id, control) {
1272     var from_rowIndex = this.list_rows[this.shift_start].obj.rowIndex;
b11a00 1273     var to_rowIndex = this.list_rows[id].obj.rowIndex;
T 1274         
1275     var i = ((from_rowIndex < to_rowIndex)? from_rowIndex : to_rowIndex);
1276     var j = ((from_rowIndex > to_rowIndex)? from_rowIndex : to_rowIndex);
1277     
1278     // iterate through the entire message list
1279     for (var n in this.list_rows) {
1280       if ((this.list_rows[n].obj.rowIndex >= i) && (this.list_rows[n].obj.rowIndex <= j)) {
1281         if (!this.in_selection(n))
d58c69 1282           this.highlight_row(n, true);
b11a00 1283       } else {
T 1284         if  (this.in_selection(n) && !control)
d58c69 1285           this.highlight_row(n, true);
b11a00 1286       }
T 1287     }
1288   };
1289   
4e17e6 1290
T 1291   this.clear_selection = function()
1292     {
1293     for(var n=0; n<this.selection.length; n++)
1294       if (this.list_rows[this.selection[n]])
1295         this.set_classname(this.list_rows[this.selection[n]].obj, 'selected', false);
1296
1297     this.selection = new Array();    
1298     };
1299
1300
1301   // check if given id is part of the current selection
1302   this.in_selection = function(id)
1303     {
1304     for(var n in this.selection)
1305       if (this.selection[n]==id)
1306         return true;
1307
1308     return false;    
1309     };
1310
1311
1312   // select each row in list
1313   this.select_all = function(filter)
1314     {
1315     if (!this.list_rows || !this.list_rows.length)
1316       return false;
1317       
1318     // reset selection first
1319     this.clear_selection();
1320     
1321     for (var n in this.list_rows)
1322       if (!filter || this.list_rows[n][filter]==true)
2a1e18 1323       this.highlight_row(n, true);
4e17e6 1324     };
T 1325     
1326
1327   // when user doble-clicks on a row
1328   this.show_message = function(id, safe)
1329     {
1330     var add_url = '';
1331     var target = window;
1332     if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
1333       {
1334       target = window.frames[this.env.contentframe];
1335       add_url = '&_framed=1';
1336       }
1337       
1338     if (safe)
1339       add_url = '&_safe=1';
1340
1341     if (id)
1342       {
09941e 1343       this.set_busy(true, 'loading');
4e17e6 1344       target.location.href = this.env.comm_path+'&_action=show&_uid='+id+'&_mbox='+escape(this.env.mailbox)+add_url;
T 1345       }
1346     };
1347
1348
1349
1350   // list a specific page
1351   this.list_page = function(page)
1352     {
1353     if (page=='next')
1354       page = this.env.current_page+1;
1355     if (page=='prev' && this.env.current_page>1)
1356       page = this.env.current_page-1;
1357       
1358     if (page > 0 && page <= this.env.pagecount)
1359       {
1360       this.env.current_page = page;
1361       
1362       if (this.task=='mail')
1363         this.list_mailbox(this.env.mailbox, page);
1364       else if (this.task=='addressbook')
1365         this.list_contacts(page);
1366       }
1367     };
1368
1369
1370   // list messages of a specific mailbox
f3b659 1371   this.list_mailbox = function(mbox, page, sort)
4e17e6 1372     {
T 1373     var add_url = '';
1374     var target = window;
1375
1376     if (!mbox)
1377       mbox = this.env.mailbox;
1378
f3b659 1379     // add sort to url if set
T 1380     if (sort)
1381       add_url += '&_sort=' + sort;
1382       
4e17e6 1383     // set page=1 if changeing to another mailbox
T 1384     if (!page && mbox != this.env.mailbox)
1385       {
1386       page = 1;
9fee0e 1387       add_url += '&_refresh=1';
4e17e6 1388       this.env.current_page = page;
T 1389       this.clear_selection();
1390       }
4647e1 1391     
T 1392     // also send search request to get the right messages
1393     if (this.env.search_request)
1394       add_url += '&_search='+this.env.search_request;
4e17e6 1395       
T 1396     if (this.env.mailbox!=mbox)
1397       this.select_mailbox(mbox);
1398
1399     // load message list remotely
1400     if (this.gui_objects.messagelist)
1401       {
9fee0e 1402       this.list_mailbox_remote(mbox, page, add_url);
4e17e6 1403       return;
T 1404       }
1405     
1406     if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
1407       {
1408       target = window.frames[this.env.contentframe];
9fee0e 1409       add_url += '&_framed=1';
4e17e6 1410       }
T 1411
1412     // load message list to target frame/window
1413     if (mbox)
1414       {
1415       this.set_busy(true, 'loading');
1416       target.location.href = this.env.comm_path+'&_mbox='+escape(mbox)+(page ? '&_page='+page : '')+add_url;
1417       }
1418     };
1419
1420
1421   // send remote request to load message list
9fee0e 1422   this.list_mailbox_remote = function(mbox, page, add_url)
4e17e6 1423     {
15a9d1 1424     // clear message list first
T 1425     this.clear_message_list();
1426
1427     // send request to server
1428     var url = '_mbox='+escape(mbox)+(page ? '&_page='+page : '');
1429     this.set_busy(true, 'loading');
1430     this.http_request('list', url+add_url, true);
1431     };
1432
1433
1434   this.clear_message_list = function()
1435     {
4e17e6 1436     var table = this.gui_objects.messagelist;
T 1437     var tbody = document.createElement('TBODY');
1438     table.insertBefore(tbody, table.tBodies[0]);
1439     table.removeChild(table.tBodies[1]);
1440     
1441     this.message_rows = new Array();
1442     this.list_rows = this.message_rows;
15a9d1 1443     
T 1444     };
1445
1446
1447   this.expunge_mailbox = function(mbox)
1448     {
1449     var lock = false;
1450     var add_url = '';
1451     
1452     // lock interface if it's the active mailbox
1453     if (mbox == this.env.mailbox)
1454        {
1455        lock = true;
1456        this.set_busy(true, 'loading');
1457        add_url = '&_reload=1';
1458        }
4e17e6 1459
T 1460     // send request to server
15a9d1 1461     var url = '_mbox='+escape(mbox);
T 1462     this.http_request('expunge', url+add_url, lock);
4e17e6 1463     };
T 1464
1465
5e3512 1466   this.purge_mailbox = function(mbox)
T 1467     {
1468     var lock = false;
1469     var add_url = '';
1470     
1471     if (!confirm(this.get_label('purgefolderconfirm')))
1472       return false;
1473     
1474     // lock interface if it's the active mailbox
1475     if (mbox == this.env.mailbox)
1476        {
1477        lock = true;
1478        this.set_busy(true, 'loading');
1479        add_url = '&_reload=1';
1480        }
1481
1482     // send request to server
1483     var url = '_mbox='+escape(mbox);
1484     this.http_request('purge', url+add_url, lock);
1485     };
1486     
1487
4e17e6 1488   // move selected messages to the specified mailbox
T 1489   this.move_messages = function(mbox)
1490     {
1491     // exit if no mailbox specified or if selection is empty
1492     if (!mbox || !(this.selection.length || this.env.uid) || mbox==this.env.mailbox)
1493       return;
1494     
1495     var a_uids = new Array();
1496
1497     if (this.env.uid)
1498       a_uids[a_uids.length] = this.env.uid;
1499     else
1500       {
1501       var id;
1502       for (var n=0; n<this.selection.length; n++)
1503         {
1504         id = this.selection[n];
1505         a_uids[a_uids.length] = id;
1506       
1507         // 'remove' message row from list (just hide it)
1508         if (this.message_rows[id].obj)
1509           this.message_rows[id].obj.style.display = 'none';
1510         }
1511       }
ecf759 1512       
T 1513     var lock = false;
4e17e6 1514
T 1515     // show wait message
1516     if (this.env.action=='show')
ecf759 1517       {
T 1518       lock = true;
4e17e6 1519       this.set_busy(true, 'movingmessage');
ecf759 1520       }
4e17e6 1521
T 1522     // send request to server
ecf759 1523     this.http_request('moveto', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_target_mbox='+escape(mbox)+'&_from='+(this.env.action ? this.env.action : ''), lock);
4e17e6 1524     };
T 1525
1526
1527   // delete selected messages from the current mailbox
1528   this.delete_messages = function()
1529     {
1530     // exit if no mailbox specified or if selection is empty
1531     if (!(this.selection.length || this.env.uid))
1532       return;
1533     
1534     var a_uids = new Array();
1535
1536     if (this.env.uid)
1537       a_uids[a_uids.length] = this.env.uid;
1538     else
1539       {
1540       var id;
1541       for (var n=0; n<this.selection.length; n++)
1542         {
1543         id = this.selection[n];
1544         a_uids[a_uids.length] = id;
1545       
1546         // 'remove' message row from list (just hide it)
1547         if (this.message_rows[id].obj)
1548           this.message_rows[id].obj.style.display = 'none';
1549         }
1550       }
1551
1552     // send request to server
1553     this.http_request('delete', '_uid='+a_uids.join(',')+'&_mbox='+escape(this.env.mailbox)+'&_from='+(this.env.action ? this.env.action : ''));
1554     };
1555
1556
1557   // set a specific flag to one or more messages
1558   this.mark_message = function(flag, uid)
1559     {
1560     var a_uids = new Array();
1561     
1562     if (uid)
1563       a_uids[0] = uid;
1564     else if (this.env.uid)
1565       a_uids[0] = this.env.uid;
1566     else
1567       {
1568       var id;
1569       for (var n=0; n<this.selection.length; n++)
1570         {
1571         id = this.selection[n];
1572         a_uids[a_uids.length] = id;
1573       
1574         // 'remove' message row from list (just hide it)
1575         if (this.message_rows[id].obj)
1576           this.message_rows[id].obj.style.display = 'none';
1577         }
1578       }
1579
1580     // mark all message rows as read/unread
1581     var icn_src;
1582     for (var i=0; i<a_uids.length; i++)
1583       {
1584       uid = a_uids[i];
1585       if (this.message_rows[uid])
1586         {
1587         this.message_rows[uid].unread = (flag=='unread' ? true : false);
1588         
1589         if (this.message_rows[uid].classname.indexOf('unread')<0 && this.message_rows[uid].unread)
1590           {
1591           this.message_rows[uid].classname += ' unread';
fd660a 1592           this.set_classname(this.message_rows[uid].obj, 'unread', true);
T 1593
4e17e6 1594           if (this.env.unreadicon)
T 1595             icn_src = this.env.unreadicon;
1596           }
1597         else if (!this.message_rows[uid].unread)
1598           {
1599           this.message_rows[uid].classname = this.message_rows[uid].classname.replace(/\s*unread/, '');
fd660a 1600           this.set_classname(this.message_rows[uid].obj, 'unread', false);
4e17e6 1601
T 1602           if (this.message_rows[uid].replied && this.env.repliedicon)
1603             icn_src = this.env.repliedicon;
1604           else if (this.env.messageicon)
1605             icn_src = this.env.messageicon;
1606           }
1607
1608         if (this.message_rows[uid].icon && icn_src)
1609           this.message_rows[uid].icon.src = icn_src;
1610         }
1611       }
1612
1613     // send request to server
1614     this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
1615     };
1616
1617
1618
1619   /*********************************************************/
1620   /*********        message compose methods        *********/
1621   /*********************************************************/
1cded8 1622   
T 1623   
977a29 1624   // checks the input fields before sending a message
T 1625   this.check_compose_input = function()
1626     {
1627     // check input fields
1628     var input_to = rcube_find_object('_to');
1629     var input_subject = rcube_find_object('_subject');
1630     var input_message = rcube_find_object('_message');
1631
1632     // check for empty recipient
1633     if (input_to && !rcube_check_email(input_to.value, true))
1634       {
1635       alert(this.get_label('norecipientwarning'));
1636       input_to.focus();
1637       return false;
1638       }
1639
1640     // display localized warning for missing subject
1641     if (input_subject && input_subject.value == '')
1642       {
1643       var subject = prompt(this.get_label('nosubjectwarning'), this.get_label('nosubject'));
1644
1645       // user hit cancel, so don't send
1646       if (!subject && subject !== '')
1647         {
1648         input_subject.focus();
1649         return false;
1650         }
1651       else
1652         {
1653         input_subject.value = subject ? subject : this.get_label('nosubject');            
1654         }
1655       }
1656
1657     // check for empty body
1658     if (input_message.value=='')
1659       {
1660       if (!confirm(this.get_label('nobodywarning')))
1661         {
1662         input_message.focus();
1663         return false;
1664         }
1665       }
1666
1667     return true;
1668     };
1669     
1670     
1671   this.compose_field_hash = function()
1672     {
1673     // check input fields
1674     var input_to = rcube_find_object('_to');
1675     var input_cc = rcube_find_object('_to');
1676     var input_bcc = rcube_find_object('_to');
1677     var input_subject = rcube_find_object('_subject');
1678     var input_message = rcube_find_object('_message');
1679     
1680     var str = '';
1681     if (input_to && input_to.value)
1682       str += input_to.value+':';
1683     if (input_cc && input_cc.value)
1684       str += input_cc.value+':';
1685     if (input_bcc && input_bcc.value)
1686       str += input_bcc.value+':';
1687     if (input_subject && input_subject.value)
1688       str += input_subject.value+':';
1689     if (input_message && input_message.value)
1690       str += input_message.value;
1691
1692     return str;
1693     };
1694     
1695   
1cded8 1696   this.change_identity = function(obj)
T 1697     {
1698     if (!obj || !obj.options)
1699       return false;
1700
1701     var id = obj.options[obj.selectedIndex].value;
1702     var input_message = rcube_find_object('_message');
1703     var message = input_message ? input_message.value : '';
749b07 1704     var sig, p;
1cded8 1705
T 1706     // remove the 'old' signature
1707     if (this.env.identity && this.env.signatures && this.env.signatures[this.env.identity])
1708       {
749b07 1709       sig = this.env.signatures[this.env.identity];
T 1710       if (sig.indexOf('-- ')!=0)
1711         sig = '-- \n'+sig;
1712
1713       p = message.lastIndexOf(sig);
1714       if (p>=0)
1cded8 1715         message = message.substring(0, p-1) + message.substring(p+sig.length, message.length);
T 1716       }
1717
1718     // add the new signature string
1719     if (this.env.signatures && this.env.signatures[id])
1720       {
749b07 1721       sig = this.env.signatures[id];
T 1722       if (sig.indexOf('-- ')!=0)
1723         sig = '-- \n'+sig;
1cded8 1724       message += '\n'+sig;
T 1725       }
1726
749b07 1727     if (input_message)
1cded8 1728       input_message.value = message;
T 1729       
1730     this.env.identity = id;
1731     };
4e17e6 1732
T 1733
1734   this.show_attachment_form = function(a)
1735     {
1736     if (!this.gui_objects.uploadbox)
1737       return false;
1738       
1739     var elm, list;
1740     if (elm = this.gui_objects.uploadbox)
1741       {
1742       if (a &&  (list = this.gui_objects.attachmentlist))
1743         {
1744         var pos = rcube_get_object_pos(list);
1745         var left = pos.x;
1746         var top = pos.y + list.offsetHeight + 10;
1747       
1748         elm.style.top = top+'px';
1749         elm.style.left = left+'px';
1750         }
1751       
1752       elm.style.visibility = a ? 'visible' : 'hidden';
1753       }
1754       
1755     // clear upload form
1756     if (!a && this.gui_objects.attachmentform && this.gui_objects.attachmentform!=this.gui_objects.messageform)
1757       this.gui_objects.attachmentform.reset();
1758     };
1759
1760
1761   // upload attachment file
1762   this.upload_file = function(form)
1763     {
1764     if (!form)
1765       return false;
1766       
1767     // get file input fields
1768     var send = false;
1769     for (var n=0; n<form.elements.length; n++)
1770       if (form.elements[n].type=='file' && form.elements[n].value)
1771         {
1772         send = true;
1773         break;
1774         }
1775     
1776     // create hidden iframe and post upload form
1777     if (send)
1778       {
1779       var ts = new Date().getTime();
1780       var frame_name = 'rcmupload'+ts;
1781
1782       // have to do it this way for IE
1783       // otherwise the form will be posted to a new window
1784       if(document.all && !window.opera)
1785         {
1786         var html = '<iframe name="'+frame_name+'" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>';
1787         document.body.insertAdjacentHTML('BeforeEnd',html);
1788         }
1789       else  // for standards-compilant browsers
1790         {
1791         var frame = document.createElement('IFRAME');
1792         frame.name = frame_name;
1793         frame.width = 10;
1794         frame.height = 10;
1795         frame.style.visibility = 'hidden';
1796         document.body.appendChild(frame);
1797         }
1798
1799       form.target = frame_name;
1800       form.action = this.env.comm_path+'&_action=upload';
1801       form.setAttribute('enctype', 'multipart/form-data');
1802       form.submit();
1803       }
1804     
1805     // set reference to the form object
1806     this.gui_objects.attachmentform = form;
1807     };
1808
1809
1810   // add file name to attachment list
1811   // called from upload page
1812   this.add2attachment_list = function(name)
1813     {
1814     if (!this.gui_objects.attachmentlist)
1815       return false;
1816       
1817     var li = document.createElement('LI');
1818     li.innerHTML = name;
1819     this.gui_objects.attachmentlist.appendChild(li);
1820     };
1821
1822
1823   // send remote request to add a new contact
1824   this.add_contact = function(value)
1825     {
1826     if (value)
1827       this.http_request('addcontact', '_address='+value);
1828     };
1829
4647e1 1830   // send remote request to search mail
T 1831   this.qsearch = function(value, mbox)
1832     {
1833     if (value && mbox)
1834       {
1835       this.clear_message_list();
1836       this.set_busy(true, 'searching');
1837       this.http_request('search', '_search='+value+'&_mbox='+mbox, true);
1838       }
1839     };
1840
1841   // reset quick-search form
1842   this.reset_qsearch = function()
1843     {
1844     if (this.gui_objects.qsearchbox)
1845       this.gui_objects.qsearchbox.value = '';
1846       
1847     this.env.search_request = null;
1848     };
1849     
4e17e6 1850
T 1851   /*********************************************************/
1852   /*********     keyboard live-search methods      *********/
1853   /*********************************************************/
1854
1855
1856   // handler for keyboard events on address-fields
1857   this.ksearch_keypress = function(e, obj)
1858     {
1859     if (typeof(this.env.contacts)!='object' || !this.env.contacts.length)
1860       return true;
1861
1862     if (this.ksearch_timer)
1863       clearTimeout(this.ksearch_timer);
1864
1865     if (!e)
1866       e = window.event;
1867       
1868     var highlight;
1869     var key = e.keyCode ? e.keyCode : e.which;
1870
1871     switch (key)
1872       {
1873       case 38:  // key up
1874       case 40:  // key down
1875         if (!this.ksearch_pane)
1876           break;
1877           
1878         var dir = key==38 ? 1 : 0;
1879         var next;
1880         
1881         highlight = document.getElementById('rcmksearchSelected');
1882         if (!highlight)
1883           highlight = this.ksearch_pane.ul.firstChild;
1884         
1885         if (highlight && (next = dir ? highlight.previousSibling : highlight.nextSibling))
1886           {
1887           highlight.removeAttribute('id');
1888           //highlight.removeAttribute('class');
1889           this.set_classname(highlight, 'selected', false);
1890           }
1891
1892         if (next)
1893           {
1894           next.setAttribute('id', 'rcmksearchSelected');
1895           this.set_classname(next, 'selected', true);
1896           this.ksearch_selected = next._rcm_id;
1897           }
1898
1899         if (e.preventDefault)
1900           e.preventDefault();
1901         return false;
1902
1903       case 9:  // tab
1904         if(e.shiftKey)
1905           break;
1906
1907       case 13:  // enter     
1908         if (this.ksearch_selected===null || !this.ksearch_input || !this.ksearch_value)
1909           break;
1910
1911         // get cursor pos
1912         var inp_value = this.ksearch_input.value.toLowerCase();
1913         var cpos = this.get_caret_pos(this.ksearch_input);
1914         var p = inp_value.lastIndexOf(this.ksearch_value, cpos);
1915         
1916         // replace search string with full address
1917         var pre = this.ksearch_input.value.substring(0, p);
1918         var end = this.ksearch_input.value.substring(p+this.ksearch_value.length, this.ksearch_input.value.length);
1919         var insert = this.env.contacts[this.ksearch_selected]+', ';
1920         this.ksearch_input.value = pre + insert + end;
1921         
1922         //this.ksearch_input.value = this.ksearch_input.value.substring(0, p)+insert;
1923         
1924         // set caret to insert pos
1925         cpos = p+insert.length;
1926         if (this.ksearch_input.setSelectionRange)
1927           this.ksearch_input.setSelectionRange(cpos, cpos);
1928         
1929         // hide ksearch pane
1930         this.ksearch_hide();
1931       
1932         if (e.preventDefault)
1933           e.preventDefault();
1934         return false;
1935
1936       case 27:  // escape
1937         this.ksearch_hide();
1938         break;
1939
1940       }
1941
1942     // start timer
1943     this.ksearch_timer = setTimeout(this.ref+'.ksearch_get_results()', 200);      
1944     this.ksearch_input = obj;
1945     
1946     return true;
1947     };
1948
1949
1950   // address search processor
1951   this.ksearch_get_results = function()
1952     {
1953     var inp_value = this.ksearch_input ? this.ksearch_input.value : null;
1954     if (inp_value===null)
1955       return;
1956
1957     // get string from current cursor pos to last comma
1958     var cpos = this.get_caret_pos(this.ksearch_input);
1959     var p = inp_value.lastIndexOf(',', cpos-1);
1960     var q = inp_value.substring(p+1, cpos);
1961
1962     // trim query string
1963     q = q.replace(/(^\s+|\s+$)/g, '').toLowerCase();
1964
1965     if (!q.length || q==this.ksearch_value)
1966       {
1967       if (!q.length && this.ksearch_pane && this.ksearch_pane.visible)
1968         this.ksearch_pane.show(0);
1969
1970       return;
1971       }
1972
1973     this.ksearch_value = q;
1974     
1975     // start searching the contact list
1976     var a_results = new Array();
1977     var a_result_ids = new Array();
1978     var c=0;
1979     for (var i=0; i<this.env.contacts.length; i++)
1980       {
1981       if (this.env.contacts[i].toLowerCase().indexOf(q)>=0)
1982         {
1983         a_results[c] = this.env.contacts[i];
1984         a_result_ids[c++] = i;
1985         
1986         if (c==15)  // limit search results
1987           break;
1988         }
1989       }
1990
1991     // display search results
1992     if (c && a_results.length)
1993       {
1994       var p, ul, li;
1995       
1996       // create results pane if not present
1997       if (!this.ksearch_pane)
1998         {
1999         ul = document.createElement('UL');
2000         this.ksearch_pane = new rcube_layer('rcmKSearchpane', {vis:0, zindex:30000});
2001         this.ksearch_pane.elm.appendChild(ul);
2002         this.ksearch_pane.ul = ul;
2003         }
2004       else
2005         ul = this.ksearch_pane.ul;
2006
2007       // remove all search results
2008       ul.innerHTML = '';
2009             
2010       // add each result line to list
2011       for (i=0; i<a_results.length; i++)
2012         {
2013         li = document.createElement('LI');
2014         li.innerHTML = a_results[i].replace(/</, '&lt;').replace(/>/, '&gt;');
2015         li._rcm_id = a_result_ids[i];
2016         ul.appendChild(li);
2017         }
2018
2019       // check if last selected item is still in result list
2020       if (this.ksearch_selected!==null)
2021         {
2022         p = find_in_array(this.ksearch_selected, a_result_ids);
2023         if (p>=0 && ul.childNodes)
2024           {
2025           ul.childNodes[p].setAttribute('id', 'rcmksearchSelected');
2026           this.set_classname(ul.childNodes[p], 'selected', true);
2027           }
2028         else
2029           this.ksearch_selected = null;
2030         }
2031       
2032       // if no item selected, select the first one
2033       if (this.ksearch_selected===null)
2034         {
2035         ul.firstChild.setAttribute('id', 'rcmksearchSelected');
2036         this.set_classname(ul.firstChild, 'selected', true);
2037         this.ksearch_selected = a_result_ids[0];
2038         }
2039
2040       // resize the containing layer to fit the list
2041       //this.ksearch_pane.resize(ul.offsetWidth, ul.offsetHeight);
2042     
2043       // move the results pane right under the input box and make it visible
2044       var pos = rcube_get_object_pos(this.ksearch_input);
2045       this.ksearch_pane.move(pos.x, pos.y+this.ksearch_input.offsetHeight);
2046       this.ksearch_pane.show(1); 
2047       }
2048     // hide results pane
2049     else
2050       this.ksearch_hide();
2051     };
2052
2053
2054   this.ksearch_blur = function(e, obj)
2055     {
2056     if (this.ksearch_timer)
2057       clearTimeout(this.ksearch_timer);
2058
2059     this.ksearch_value = '';      
2060     this.ksearch_input = null;
2061     
2062     this.ksearch_hide();
2063     };
2064
2065
2066   this.ksearch_hide = function()
2067     {
2068     this.ksearch_selected = null;
2069     
2070     if (this.ksearch_pane)
2071       this.ksearch_pane.show(0);    
2072     };
2073
2074
2075
2076   /*********************************************************/
2077   /*********         address book methods          *********/
2078   /*********************************************************/
2079
2080
2081   this.list_contacts = function(page)
2082     {
2083     var add_url = '';
2084     var target = window;
2085     
2086     if (page && this.current_page==page)
2087       return false;
2088
2089     // load contacts remotely
2090     if (this.gui_objects.contactslist)
2091       {
2092       this.list_contacts_remote(page);
2093       return;
2094       }
2095
2096     if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
2097       {
2098       target = window.frames[this.env.contentframe];
2099       add_url = '&_framed=1';
2100       }
2101
2102     this.set_busy(true, 'loading');
2103     location.href = this.env.comm_path+(page ? '&_page='+page : '')+add_url;
2104     };
2105
2106
2107   // send remote request to load contacts list
2108   this.list_contacts_remote = function(page)
2109     {
2110     // clear list
2111     var table = this.gui_objects.contactslist;
2112     var tbody = document.createElement('TBODY');
2113     table.insertBefore(tbody, table.tBodies[0]);
2114     table.tBodies[1].style.display = 'none';
2115     
2116     this.contact_rows = new Array();
2117     this.list_rows = this.contact_rows;
2118
2119     // send request to server
2120     var url = page ? '&_page='+page : '';
2121     this.set_busy(true, 'loading');
ecf759 2122     this.http_request('list', url, true);
4e17e6 2123     };
T 2124
2125
2126   // load contact record
2127   this.load_contact = function(cid, action, framed)
2128     {
2129     var add_url = '';
2130     var target = window;
2131     if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
2132       {
2133       add_url = '&_framed=1';
2134       target = window.frames[this.env.contentframe];
2135       document.getElementById(this.env.contentframe).style.visibility = 'inherit';
2136       }
2137     else if (framed)
2138       return false;
2139       
2140     //if (this.env.framed && add_url=='')
5e3512 2141     
4e17e6 2142     //  add_url = '&_framed=1';
T 2143     
2144     if (action && (cid || action=='add'))
2145       {
2146       this.set_busy(true);
2147       target.location.href = this.env.comm_path+'&_action='+action+'&_cid='+cid+add_url;
2148       }
2149     };
2150
2151
2152   this.delete_contacts = function()
2153     {
2154     // exit if no mailbox specified or if selection is empty
5e3512 2155     if (!(this.selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm')))
4e17e6 2156       return;
5e3512 2157       
4e17e6 2158     var a_cids = new Array();
T 2159
2160     if (this.env.cid)
2161       a_cids[a_cids.length] = this.env.cid;
2162     else
2163       {
2164       var id;
2165       for (var n=0; n<this.selection.length; n++)
2166         {
2167         id = this.selection[n];
2168         a_cids[a_cids.length] = id;
2169       
2170         // 'remove' row from list (just hide it)
2171         if (this.contact_rows[id].obj)
2172           this.contact_rows[id].obj.style.display = 'none';
2173         }
2174
2175       // hide content frame if we delete the currently displayed contact
2176       if (this.selection.length==1 && this.env.contentframe)
2177         {
2178         var elm = document.getElementById(this.env.contentframe);
2179         elm.style.visibility = 'hidden';
2180         }
2181       }
2182
2183     // send request to server
2184     this.http_request('delete', '_cid='+a_cids.join(',')+'&_from='+(this.env.action ? this.env.action : ''));
2185     };
2186
2187
2188   // update a contact record in the list
2189   this.update_contact_row = function(cid, cols_arr)
2190     {
2191     if (!this.contact_rows[cid] || !this.contact_rows[cid].obj)
2192       return false;
2193       
2194     var row = this.contact_rows[cid].obj;
2195     for (var c=0; c<cols_arr.length; c++)
2196       if (row.cells[c])
2197         row.cells[c].innerHTML = cols_arr[c];
2198
2199     };
2200   
d1d2c4 2201   
S 2202   // load ldap search form
2203   this.ldappublicsearch = function(action)
2204     {
2205     var add_url = '';
2206     var target = window;
2207     if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
2208       {
2209       add_url = '&_framed=1';
2210       target = window.frames[this.env.contentframe];
2211       document.getElementById(this.env.contentframe).style.visibility = 'inherit';
2212       }
2213     else
2214       return false; 
2215
2216
2217     if (action == 'ldappublicsearch')
2218       target.location.href = this.env.comm_path+'&_action='+action+add_url;
2219     };
2220  
2221   // add ldap contacts to address book
2222   this.add_ldap_contacts = function()
2223     {
2224     if (window.frames[this.env.contentframe].rcmail)
2225       {
2226       var frame = window.frames[this.env.contentframe];
2227
2228       // build the url
2229       var url    = '&_framed=1';
2230       var emails = '&_emails=';
2231       var names  = '&_names=';
2232       var end    = '';
2233       for (var n=0; n<frame.rcmail.selection.length; n++)
2234         {
2235         end = n < frame.rcmail.selection.length - 1 ? ',' : '';
2236         emails += frame.rcmail.ldap_contact_rows[frame.rcmail.selection[n]].obj.cells[1].innerHTML + end;
2237         names  += frame.rcmail.ldap_contact_rows[frame.rcmail.selection[n]].obj.cells[0].innerHTML + end;
2238         }
2239        
2240       frame.location.href = this.env.comm_path + '&_action=save&_framed=1' + emails + names;
2241       }
2242     return false;
2243     }
2244   
4e17e6 2245
T 2246
2247   /*********************************************************/
2248   /*********        user settings methods          *********/
2249   /*********************************************************/
2250
2251
2252   // load contact record
2253   this.load_identity = function(id, action)
2254     {
2255     if (action=='edit-identity' && (!id || id==this.env.iid))
2256       return;
2257
2258     var add_url = '';
2259     var target = window;
2260     if (this.env.contentframe && window.frames && window.frames[this.env.contentframe])
2261       {
2262       add_url = '&_framed=1';
2263       target = window.frames[this.env.contentframe];
2264       document.getElementById(this.env.contentframe).style.visibility = 'inherit';
2265       }
2266
2267     if (action && (id || action=='add-identity'))
2268       {
2269       this.set_busy(true);
2270       target.location.href = this.env.comm_path+'&_action='+action+'&_iid='+id+add_url;
2271       }
2272     };
2273
2274
2275
2276   this.delete_identity = function(id)
2277     {
2278     // exit if no mailbox specified or if selection is empty
2279     if (!(this.selection.length || this.env.iid))
2280       return;
2281     
2282     if (!id)
2283       id = this.env.iid ? this.env.iid : this.selection[0];
2284
2285 /*
2286     // 'remove' row from list (just hide it)
2287     if (this.identity_rows && this.identity_rows[id].obj)
2288       {
2289       this.clear_selection();
2290       this.identity_rows[id].obj.style.display = 'none';
2291       }
2292 */
2293
2294     // if (this.env.framed && id)
2295       this.set_busy(true);
2296       location.href = this.env.comm_path+'&_action=delete-identity&_iid='+id;
2297     // else if (id)
2298     //  this.http_request('delete-identity', '_iid='+id);
2299     };
2300
2301
2302   this.create_folder = function(name)
2303     {
2304     var form;
2305     if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
2306       name = form.elements['_folder_name'].value;
2307
2308     if (name)
ecf759 2309       this.http_request('create-folder', '_name='+escape(name), true);
4e17e6 2310     else if (form.elements['_folder_name'])
T 2311       form.elements['_folder_name'].focus();
2312     };
2313
2314
2315   this.delete_folder = function(folder)
2316     {
2317     if (folder)
2318       {
2319       this.http_request('delete-folder', '_mboxes='+escape(folder));
2320       }
1cded8 2321     };
T 2322
2323
2324   this.remove_folder_row = function(folder)
2325     {
2326     for (var id in this.env.subscriptionrows)
2327       if (this.env.subscriptionrows[id]==folder)
2328         break;
2329
2330     var row;
2331     if (id && (row = document.getElementById(id)))
2332       row.style.display = 'none';    
4e17e6 2333     };
T 2334
2335
2336   this.subscribe_folder = function(folder)
2337     {
2338     var form;
2339     if ((form = this.gui_objects.editform) && form.elements['_unsubscribed'])
2340       this.change_subscription('_unsubscribed', '_subscribed', 'subscribe');
2341     else if (folder)
2342       this.http_request('subscribe', '_mboxes='+escape(folder));
2343     };
2344
2345
2346   this.unsubscribe_folder = function(folder)
2347     {
2348     var form;
2349     if ((form = this.gui_objects.editform) && form.elements['_subscribed'])
2350       this.change_subscription('_subscribed', '_unsubscribed', 'unsubscribe');
2351     else if (folder)
2352       this.http_request('unsubscribe', '_mboxes='+escape(folder));
2353     };
2354     
2355
2356   this.change_subscription = function(from, to, action)
2357     {
2358     var form;
2359     if (form = this.gui_objects.editform)
2360       {
2361       var a_folders = new Array();
2362       var list_from = form.elements[from];
2363
2364       for (var i=0; list_from && i<list_from.options.length; i++)
2365         {
2366         if (list_from.options[i] && list_from.options[i].selected)
2367           {
2368           a_folders[a_folders.length] = list_from.options[i].value;
2369           list_from[i] = null;
2370           i--;
2371           }
2372         }
2373
2374       // yes, we have some folders selected
2375       if (a_folders.length)
2376         {
2377         var list_to = form.elements[to];
2378         var index;
2379         
2380         for (var n=0; n<a_folders.length; n++)
2381           {
2382           index = list_to.options.length;
2383           list_to[index] = new Option(a_folders[n]);
2384           }
2385           
2386         this.http_request(action, '_mboxes='+escape(a_folders.join(',')));
2387         }
2388       }
2389       
2390     };
2391
2392
2393    // add a new folder to the subscription list by cloning a folder row
2394    this.add_folder_row = function(name)
2395      {
2396      if (!this.gui_objects.subscriptionlist)
2397        return false;
2398
2399      var tbody = this.gui_objects.subscriptionlist.tBodies[0];
2400      var id = tbody.childNodes.length+1;
2401      
2402      // clone a table row
2403      var row = this.clone_table_row(tbody.rows[0]);
2404      row.id = 'rcmrow'+id;
2405      tbody.appendChild(row);
2406
2407      // add to folder/row-ID map
2408      this.env.subscriptionrows[row.id] = name;
2409
2410      // set folder name
2411      row.cells[0].innerHTML = name;
2412      if (row.cells[1].firstChild.tagName=='INPUT')
2413        {
2414        row.cells[1].firstChild.value = name;
2415        row.cells[1].firstChild.checked = true;
2416        }
2417      if (row.cells[2].firstChild.tagName=='A')
2418        row.cells[2].firstChild.onclick = new Function(this.ref+".command('delete-folder','"+name+"')");
14eafe 2419
T 2420     var form;
2421     if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
2422       form.elements['_folder_name'].value = '';
4e17e6 2423      };
T 2424
2425
2426   // duplicate a specific table row
2427   this.clone_table_row = function(row)
2428     {
2429     var cell, td;
2430     var new_row = document.createElement('TR');
2431     for(var n=0; n<row.childNodes.length; n++)
2432       {
2433       cell = row.childNodes[n];
2434       td = document.createElement('TD');
2435
2436       if (cell.className)
2437         td.className = cell.className;
2438       if (cell.align)
2439         td.setAttribute('align', cell.align);
2440         
2441       td.innerHTML = cell.innerHTML;
2442       new_row.appendChild(td);
2443       }
2444     
2445     return new_row;
2446     };
2447
2448
2449   /*********************************************************/
2450   /*********           GUI functionality           *********/
2451   /*********************************************************/
2452
2453
2454   // eable/disable buttons for page shifting
2455   this.set_page_buttons = function()
2456     {
2457     this.enable_command('nextpage', (this.env.pagecount > this.env.current_page));
2458     this.enable_command('previouspage', (this.env.current_page > 1));
2459     }
2460
2461
2462   // set button to a specific state
2463   this.set_button = function(command, state)
2464     {
2465     var a_buttons = this.buttons[command];
2466     var button, obj;
2467
2468     if(!a_buttons || !a_buttons.length)
2469       return;
2470
2471     for(var n=0; n<a_buttons.length; n++)
2472       {
2473       button = a_buttons[n];
2474       obj = document.getElementById(button.id);
2475
2476       // get default/passive setting of the button
2477       if (obj && button.type=='image' && !button.status)
2478         button.pas = obj._original_src ? obj._original_src : obj.src;
2479       else if (obj && !button.status)
2480         button.pas = String(obj.className);
2481
2482       // set image according to button state
2483       if (obj && button.type=='image' && button[state])
2484         {
2485         button.status = state;        
2486         obj.src = button[state];
2487         }
2488       // set class name according to button state
2489       else if (obj && typeof(button[state])!='undefined')
2490         {
2491         button.status = state;        
2492         obj.className = button[state];        
2493         }
2494       // disable/enable input buttons
2495       if (obj && button.type=='input')
2496         {
2497         button.status = state;
2498         obj.disabled = !state;
2499         }
2500       }
2501     };
2502
2503
2504   // mouse over button
2505   this.button_over = function(command, id)
2506     {
2507     var a_buttons = this.buttons[command];
2508     var button, img;
2509
2510     if(!a_buttons || !a_buttons.length)
2511       return;
2512
2513     for(var n=0; n<a_buttons.length; n++)
2514       {
2515       button = a_buttons[n];
2516       if(button.id==id && button.status=='act')
2517         {
2518         img = document.getElementById(button.id);
2519         if (img && button.over)
2520           img.src = button.over;
2521         }
2522       }
2523     };
2524
2525
2526   // mouse out of button
2527   this.button_out = function(command, id)
2528     {
2529     var a_buttons = this.buttons[command];
2530     var button, img;
2531
2532     if(!a_buttons || !a_buttons.length)
2533       return;
2534
2535     for(var n=0; n<a_buttons.length; n++)
2536       {
2537       button = a_buttons[n];
2538       if(button.id==id && button.status=='act')
2539         {
2540         img = document.getElementById(button.id);
2541         if (img && button.act)
2542           img.src = button.act;
2543         }
2544       }
2545     };
2546
2547
2548   // set/unset a specific class name
2549   this.set_classname = function(obj, classname, set)
2550     {
2551     var reg = new RegExp('\s*'+classname, 'i');
2552     if (!set && obj.className.match(reg))
2553       obj.className = obj.className.replace(reg, '');
2554     else if (set && !obj.className.match(reg))
2555       obj.className += ' '+classname;
2556     };
2557
2558
2559   // display a specific alttext
2560   this.alttext = function(text)
2561     {
2562     
2563     };
2564
2565
2566   // display a system message
2567   this.display_message = function(msg, type, hold)
2568     {
2569     if (!this.loaded)  // save message in order to display after page loaded
2570       {
2571       this.pending_message = new Array(msg, type);
2572       return true;
2573       }
2574     
2575     if (!this.gui_objects.message)
2576       return false;
2577       
2578     if (this.message_timer)
2579       clearTimeout(this.message_timer);
2580     
2581     var cont = msg;
2582     if (type)
2583       cont = '<div class="'+type+'">'+cont+'</div>';
a95e0e 2584
T 2585     this.gui_objects.message._rcube = this;
4e17e6 2586     this.gui_objects.message.innerHTML = cont;
T 2587     this.gui_objects.message.style.display = 'block';
a95e0e 2588     
T 2589     if (type!='loading')
2590       this.gui_objects.message.onmousedown = function(){ this._rcube.hide_message(); return true; };
4e17e6 2591     
T 2592     if (!hold)
2593       this.message_timer = setTimeout(this.ref+'.hide_message()', this.message_time);
2594     };
2595
2596
2597   // make a message row disapear
2598   this.hide_message = function()
2599     {
2600     if (this.gui_objects.message)
a95e0e 2601       {
4e17e6 2602       this.gui_objects.message.style.display = 'none';
a95e0e 2603       this.gui_objects.message.onmousedown = null;
T 2604       }
4e17e6 2605     };
T 2606
2607
2608   // mark a mailbox as selected and set environment variable
2609   this.select_mailbox = function(mbox)
2610     {
2611     if (this.gui_objects.mailboxlist)
2612       {
2613       var item, reg, text_obj;
6a35c8 2614       var s_current = this.env.mailbox.toLowerCase().replace(this.mbox_expression, '');
4e17e6 2615       var s_mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
T 2616       var s_current = this.env.mailbox.toLowerCase().replace(this.mbox_expression, '');
597170 2617       
6a35c8 2618       var current_li = document.getElementById('rcmbx'+s_current);
T 2619       var mbox_li = document.getElementById('rcmbx'+s_mbox);
2620       
2621       if (current_li)
2622         this.set_classname(current_li, 'selected', false);
2623       if (mbox_li)
2624         this.set_classname(mbox_li, 'selected', true);
4e17e6 2625       }
T 2626     
2627     this.env.mailbox = mbox;
2628     };
2629
2630
2631   // create a table row in the message list
15a9d1 2632   this.add_message_row = function(uid, cols, flags, attachment, attop)
4e17e6 2633     {
T 2634     if (!this.gui_objects.messagelist || !this.gui_objects.messagelist.tBodies[0])
2635       return false;
2636     
2637     var tbody = this.gui_objects.messagelist.tBodies[0];
2638     var rowcount = tbody.rows.length;
2639     var even = rowcount%2;
2640     
2641     this.env.messages[uid] = {replied:flags.replied?1:0,
2642                               unread:flags.unread?1:0};
2643     
2644     var row = document.createElement('TR');
2645     row.id = 'rcmrow'+uid;
15a9d1 2646     row.className = 'message '+(even ? 'even' : 'odd')+(flags.unread ? ' unread' : '')+(flags.deleted ? ' deleted' : '');
T 2647     
4e17e6 2648     if (this.in_selection(uid))
T 2649       row.className += ' selected';
2650
2651     var icon = flags.unread && this.env.unreadicon ? this.env.unreadicon :
2652                (flags.replied && this.env.repliedicon ? this.env.repliedicon : this.env.messageicon);
2653
2654     var col = document.createElement('TD');
2655     col.className = 'icon';
2656     col.innerHTML = icon ? '<img src="'+icon+'" alt="" border="0" />' : '';
2657     row.appendChild(col);
2658
2659     // add each submitted col
2660     for (var c in cols)
2661       {
2662       col = document.createElement('TD');
2663       col.className = String(c).toLowerCase();
2664       col.innerHTML = cols[c];
2665       row.appendChild(col);
2666       }
2667
2668     col = document.createElement('TD');
2669     col.className = 'icon';
2670     col.innerHTML = attachment && this.env.attachmenticon ? '<img src="'+this.env.attachmenticon+'" alt="" border="0" />' : '';
2671     row.appendChild(col);
2672     
15a9d1 2673     if (attop && tbody.rows.length)
T 2674       tbody.insertBefore(row, tbody.firstChild);
2675     else
2676       tbody.appendChild(row);
2677       
4e17e6 2678     this.init_message_row(row);
T 2679     };
2680
2681
2682   // replace content of row count display
2683   this.set_rowcount = function(text)
2684     {
2685     if (this.gui_objects.countdisplay)
2686       this.gui_objects.countdisplay.innerHTML = text;
2687
2688     // update page navigation buttons
2689     this.set_page_buttons();
2690     };
2691
58e360 2692   // replace content of quota display
T 2693    this.set_quota = function(text)
2694      {
2695      if (this.gui_objects.quotadisplay)
2696        this.gui_objects.quotadisplay.innerHTML = text;
2697      };
2698                  
4e17e6 2699
T 2700   // update the mailboxlist
15a9d1 2701   this.set_unread_count = function(mbox, count, set_title)
4e17e6 2702     {
T 2703     if (!this.gui_objects.mailboxlist)
2704       return false;
f108b9 2705       
4e17e6 2706     var item, reg, text_obj;
15a9d1 2707     mbox = String(mbox).toLowerCase().replace(this.mbox_expression, '');
T 2708     item = document.getElementById('rcmbx'+mbox);
2709
2710     if (item && item.className && item.className.indexOf('mailbox '+mbox)>=0)
4e17e6 2711       {
15a9d1 2712       // set new text
T 2713       text_obj = item.firstChild;
2714       reg = /\s+\([0-9]+\)$/i;
4e17e6 2715
15a9d1 2716       if (count && text_obj.innerHTML.match(reg))
T 2717         text_obj.innerHTML = text_obj.innerHTML.replace(reg, ' ('+count+')');
2718       else if (count)
2719         text_obj.innerHTML += ' ('+count+')';
2720       else
2721         text_obj.innerHTML = text_obj.innerHTML.replace(reg, '');
4e17e6 2722           
15a9d1 2723       // set the right classes
T 2724       this.set_classname(item, 'unread', count>0 ? true : false);
2725       }
2726
2727     // set unread count to window title
01c86f 2728     reg = /^\([0-9]+\)\s+/i;
T 2729     if (set_title && count && document.title)    
15a9d1 2730       {
T 2731       var doc_title = String(document.title);
2732
2733       if (count && doc_title.match(reg))
2734         document.title = doc_title.replace(reg, '('+count+') ');
2735       else if (count)
2736         document.title = '('+count+') '+doc_title;
2737       else
2738         document.title = doc_title.replace(reg, '');
4e17e6 2739       }
01c86f 2740     // remove unread count from window title
T 2741     else if (document.title)
2742       {
2743       document.title = document.title.replace(reg, '');
2744       }
4e17e6 2745     };
T 2746
2747
2748   // add row to contacts list
2749   this.add_contact_row = function(cid, cols)
2750     {
2751     if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
2752       return false;
2753     
2754     var tbody = this.gui_objects.contactslist.tBodies[0];
2755     var rowcount = tbody.rows.length;
2756     var even = rowcount%2;
2757     
2758     var row = document.createElement('TR');
2759     row.id = 'rcmrow'+cid;
2760     row.className = 'contact '+(even ? 'even' : 'odd');
2761     
2762     if (this.in_selection(cid))
2763       row.className += ' selected';
2764
2765     // add each submitted col
2766     for (var c in cols)
2767       {
2768       col = document.createElement('TD');
2769       col.className = String(c).toLowerCase();
2770       col.innerHTML = cols[c];
2771       row.appendChild(col);
2772       }
2773     
2774     tbody.appendChild(row);
2775     this.init_table_row(row, 'contact_rows');
2776     };
2777
2778
2779
2780   /********************************************************/
2781   /*********          drag & drop methods         *********/
2782   /********************************************************/
2783
2784
2785   this.drag_mouse_move = function(e)
2786     {
2787     if (this.drag_start)
2788       {
2789       if (!this.draglayer)
2790         this.draglayer = new rcube_layer('rcmdraglayer', {x:0, y:0, width:300, vis:0, zindex:2000});
2791       
2792       // get subjects of selectedd messages
2793       var names = '';
2794       var c, subject, obj;
2795       for(var n=0; n<this.selection.length; n++)
2796         {
2797         if (n>12)  // only show 12 lines
2798           {
2799           names += '...';
2800           break;
2801           }
2802
2803         if (this.message_rows[this.selection[n]].obj)
2804           {
2805           obj = this.message_rows[this.selection[n]].obj;
2806           subject = '';
2807
2808           for(c=0; c<obj.childNodes.length; c++)
2809             if (!subject && obj.childNodes[c].nodeName=='TD' && obj.childNodes[c].firstChild && obj.childNodes[c].firstChild.nodeType==3)
2810               {
2811               subject = obj.childNodes[c].firstChild.data;
2812               names += (subject.length > 50 ? subject.substring(0, 50)+'...' : subject) + '<br />';
2813               }
2814           }
2815         }
2816         
2817       this.draglayer.write(names);
2818       this.draglayer.show(1);
2819       }
2820
2821     var pos = this.get_mouse_pos(e);
2822     this.draglayer.move(pos.x+20, pos.y-5);
2823     
2824     this.drag_start = false;
2825     this.drag_active = true;
2826     
2827     return false;
2828     };
2829
2830
2831   this.drag_mouse_up = function()
2832     {
2833     document.onmousemove = null;
2834     
2835     if (this.draglayer && this.draglayer.visible)
2836       this.draglayer.show(0);
2837       
2838     this.drag_active = false;
2839     
2840     return false;
2841     };
2842
2843
2844
2845   /********************************************************/
2846   /*********        remote request methods        *********/
2847   /********************************************************/
2848
2849
ecf759 2850   this.http_sockets = new Array();
T 2851   
2852   // find a non-busy socket or create a new one
2853   this.get_request_obj = function()
4e17e6 2854     {
ecf759 2855     for (var n=0; n<this.http_sockets.length; n++)
4e17e6 2856       {
ecf759 2857       if (!this.http_sockets[n].busy)
T 2858         return this.http_sockets[n];
4e17e6 2859       }
ecf759 2860     
T 2861     // create a new XMLHTTP object
2862     var i = this.http_sockets.length;
2863     this.http_sockets[i] = new rcube_http_request();
4e17e6 2864
ecf759 2865     return this.http_sockets[i];
T 2866     };
2867   
2868
2869   // send a http request to the server
2870   this.http_request = function(action, querystring, lock)
2871     {
2872     var request_obj = this.get_request_obj();
4e17e6 2873     querystring += '&_remote=1';
T 2874     
2875     // add timestamp to request url to avoid cacheing problems in Safari
2876     if (bw.safari)
2877       querystring += '&_ts='+(new Date().getTime());
2878
2879     // send request
ecf759 2880     if (request_obj)
4e17e6 2881       {
T 2882       // prompt('request', this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
2883       console('HTTP request: '+this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
ecf759 2884
T 2885       if (lock)
2886         this.set_busy(true);
2887
2888       request_obj.__lock = lock ? true : false;
2889       request_obj.__action = action;
2890       request_obj.onerror = function(o){ rcube_webmail_client.http_error(o); };
2891       request_obj.oncomplete = function(o){ rcube_webmail_client.http_response(o); };
2892       request_obj.GET(this.env.comm_path+'&_action='+escape(action)+'&'+querystring);
4e17e6 2893       }
T 2894     };
2895
2896
ecf759 2897   // handle HTTP response
T 2898   this.http_response = function(request_obj)
4e17e6 2899     {
ecf759 2900     var ctype = request_obj.get_header('Content-Type');
T 2901     if (ctype)
2902       ctype = String(ctype).toLowerCase();
4e17e6 2903
ecf759 2904     if (request_obj.__lock)
4e17e6 2905       this.set_busy(false);
T 2906
5e3512 2907   console(request_obj.get_text());
4e17e6 2908
ecf759 2909     // if we get javascript code from server -> execute it
c03095 2910     if (request_obj.get_text() && (ctype=='text/javascript' || ctype=='application/x-javascript'))
T 2911       eval(request_obj.get_text());
4e17e6 2912
ecf759 2913     // process the response data according to the sent action
T 2914     switch (request_obj.__action)
2915       {
2916       case 'delete':
2917       case 'moveto':
2918         if (this.env.action=='show')
2919           this.command('list');
2920         break;
15a9d1 2921
ecf759 2922       case 'list':
5e3512 2923         if (this.env.messagecount)
T 2924           this.enable_command('purge', (this.env.mailbox==this.env.trash_mailbox));
2925
15a9d1 2926       case 'expunge':
T 2927         this.enable_command('select-all', 'select-none', 'expunge', this.env.messagecount ? true : false);
5e3512 2928         break;      
4e17e6 2929       }
ecf759 2930
T 2931     request_obj.reset();
4e17e6 2932     };
ecf759 2933
T 2934
2935   // handle HTTP request errors
2936   this.http_error = function(request_obj)
2937     {
2938     alert('Error sending request: '+request_obj.url);
2939
2940     if (request_obj.__lock)
2941       this.set_busy(false);
2942
2943     request_obj.reset();
2944     request_obj.__lock = false;
2945     };
2946
2947
2948   // use an image to send a keep-alive siganl to the server
2949   this.send_keep_alive = function()
2950     {
2951     var d = new Date();
2952     this.http_request('keep-alive', '_t='+d.getTime());
2953     };
15a9d1 2954
ecf759 2955     
15a9d1 2956   // send periodic request to check for recent messages
T 2957   this.check_for_recent = function()
2958     {
2959     var d = new Date();
2960     this.http_request('check-recent', '_t='+d.getTime());
2961     };
4e17e6 2962
T 2963
2964   /********************************************************/
2965   /*********            helper methods            *********/
2966   /********************************************************/
2967   
2968   // check if we're in show mode or if we have a unique selection
2969   // and return the message uid
2970   this.get_single_uid = function()
2971     {
2972     return this.env.uid ? this.env.uid : (this.selection.length==1 ? this.selection[0] : null);
2973     };
2974
2975   // same as above but for contacts
2976   this.get_single_cid = function()
2977     {
2978     return this.env.cid ? this.env.cid : (this.selection.length==1 ? this.selection[0] : null);
2979     };
2980
2981
8c2e58 2982 /* deprecated methods
T 2983
4e17e6 2984   // check if Shift-key is pressed on event
T 2985   this.check_shiftkey = function(e)
2986     {
2987     if(!e && window.event)
2988       e = window.event;
2989
2990     if(bw.linux && bw.ns4 && e.modifiers)
2991       return true;
2992     else if((bw.ns4 && e.modifiers & Event.SHIFT_MASK) || (e && e.shiftKey))
2993       return true;
2994     else
2995       return false;
2996     }
2997
1cded8 2998   // check if Shift-key is pressed on event
T 2999   this.check_ctrlkey = function(e)
3000     {
3001     if(!e && window.event)
3002       e = window.event;
3003
3004     if(bw.linux && bw.ns4 && e.modifiers)
3005       return true;
3006    else if (bw.mac)
3007        return this.check_shiftkey(e);
3008     else if((bw.ns4 && e.modifiers & Event.CTRL_MASK) || (e && e.ctrlKey))
3009       return true;
3010     else
3011       return false;
3012     }
8c2e58 3013 */
4e17e6 3014
8c2e58 3015   // returns modifier key (constants defined at top of file)
b11a00 3016   this.get_modifier = function(e)
T 3017     {
3018     var opcode = 0;
8c2e58 3019     e = e || window.event;
T 3020
3021     if (bw.mac && e)
3022       {
3023       opcode += (e.metaKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
3024       return opcode;    
3025       }
3026     if (e)
3027       {
b11a00 3028       opcode += (e.ctrlKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
8c2e58 3029       return opcode;
T 3030       }
b11a00 3031     if (e.cancelBubble)
8c2e58 3032       {
b11a00 3033       e.cancelBubble = true;
T 3034       e.returnValue = false;
8c2e58 3035       }
b11a00 3036     else if (e.preventDefault)
T 3037       e.preventDefault();
3038   }
3039
3040
4e17e6 3041   this.get_mouse_pos = function(e)
T 3042     {
3043     if(!e) e = window.event;
3044     var mX = (e.pageX) ? e.pageX : e.clientX;
3045     var mY = (e.pageY) ? e.pageY : e.clientY;
3046
3047     if(document.body && document.all)
3048       {
3049       mX += document.body.scrollLeft;
3050       mY += document.body.scrollTop;
3051       }
3052
3053     return { x:mX, y:mY };
3054     };
3055     
3056   
3057   this.get_caret_pos = function(obj)
3058     {
3059     if (typeof(obj.selectionEnd)!='undefined')
3060       return obj.selectionEnd;
3061
3062     else if (document.selection && document.selection.createRange)
3063       {
3064       var range = document.selection.createRange();
3065       if (range.parentElement()!=obj)
3066         return 0;
3067
3068       var gm = range.duplicate();
3069       if (obj.tagName=='TEXTAREA')
3070         gm.moveToElementText(obj);
3071       else
3072         gm.expand('textedit');
3073       
3074       gm.setEndPoint('EndToStart', range);
3075       var p = gm.text.length;
3076
3077       return p<=obj.value.length ? p : -1;
3078       }
3079
3080     else
3081       return obj.value.length;
3082     };
3083
3084
3085   this.set_caret2start = function(obj)
3086     {
3087     if (obj.createTextRange)
3088       {
3089       var range = obj.createTextRange();
3090       range.collapse(true);
3091       range.select();
3092       }
3093     else if (obj.setSelectionRange)
3094       obj.setSelectionRange(0,0);
3095
3096     obj.focus();
3097     };
3098
3099
3100   // set all fields of a form disabled
3101   this.lock_form = function(form, lock)
3102     {
3103     if (!form || !form.elements)
3104       return;
3105     
3106     var type;
3107     for (var n=0; n<form.elements.length; n++)
3108       {
3109       type = form.elements[n];
3110       if (type=='hidden')
3111         continue;
3112         
3113       form.elements[n].disabled = lock;
3114       }
3115     };
3116     
3117   }  // end object rcube_webmail
3118
3119
3120
ecf759 3121 // class for HTTP requests
T 3122 function rcube_http_request()
3123   {
3124   this.url = '';
3125   this.busy = false;
3126   this.xmlhttp = null;
3127
3128
3129   // reset object properties
3130   this.reset = function()
3131     {
3132     // set unassigned event handlers
3133     this.onloading = function(){ };
3134     this.onloaded = function(){ };
3135     this.oninteractive = function(){ };
3136     this.oncomplete = function(){ };
3137     this.onabort = function(){ };
3138     this.onerror = function(){ };
3139     
3140     this.url = '';
3141     this.busy = false;
3142     this.xmlhttp = null;
3143     }
3144
3145
3146   // create HTMLHTTP object
3147   this.build = function()
3148     {
3149     if (window.XMLHttpRequest)
3150       this.xmlhttp = new XMLHttpRequest();
3151     else if (window.ActiveXObject)
3152       this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
3153     else
3154       {
3155       
3156       }
3157     }
3158
3159   // sedn GET request
3160   this.GET = function(url)
3161     {
3162     this.build();
3163
3164     if (!this.xmlhttp)
3165       {
3166       this.onerror(this);
3167       return false;
3168       }
3169
3170     var ref = this;
3171     this.url = url;
3172     this.busy = true;
3173
3174     this.xmlhttp.onreadystatechange = function(){ ref.xmlhttp_onreadystatechange(); };
3175     this.xmlhttp.open('GET', url);
3176     this.xmlhttp.send(null);
3177     };
3178
3179
3180   this.POST = function(url, a_param)
3181     {
3182     // not implemented yet
3183     };
3184
3185
3186   // handle onreadystatechange event
3187   this.xmlhttp_onreadystatechange = function()
3188     {
3189     if(this.xmlhttp.readyState == 1)
3190       this.onloading(this);
3191
3192     else if(this.xmlhttp.readyState == 2)
3193       this.onloaded(this);
3194
3195     else if(this.xmlhttp.readyState == 3)
3196       this.oninteractive(this);
3197
3198     else if(this.xmlhttp.readyState == 4)
3199       {
3200       if(this.xmlhttp.status == 0)
3201         this.onabort(this);
3202       else if(this.xmlhttp.status == 200)
3203         this.oncomplete(this);
3204       else
3205         this.onerror(this);
3206         
3207       this.busy = false;
3208       }
3209     }
3210
3211   // getter method for HTTP headers
3212   this.get_header = function(name)
3213     {
3214     return this.xmlhttp.getResponseHeader(name);
3215     };
3216
c03095 3217   this.get_text = function()
T 3218     {
3219     return this.xmlhttp.responseText;
3220     };
3221
3222   this.get_xml = function()
3223     {
3224     return this.xmlhttp.responseXML;
3225     };
ecf759 3226
T 3227   this.reset();
3228   
3229   }  // end class rcube_http_request
3230
3231
4e17e6 3232
T 3233 function console(str)
3234   {
3235   if (document.debugform && document.debugform.console)
3236     document.debugform.console.value += str+'\n--------------------------------------\n';
3237   }
3238
3239
3240 // set onload handler
3241 window.onload = function(e)
3242   {
3243   if (window.rcube_webmail_client)
3244     rcube_webmail_client.init();
3245   };