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