move the rest of the places to use AppendImportantMessage() or GetServerStatusMsg()
[citadel.git] / webcit / useredit.c
1 /*
2  * Copyright (c) 1996-2011 by the citadel.org team
3  *
4  * This program is open source software.  You can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18
19 #include "webcit.h"
20 #include "webserver.h"
21
22
23 /*
24  *  show a list of available users to edit them
25  *  message the header message???
26  *  preselect = which user should be selected in the browser
27  */
28 void select_user_to_edit(const char *preselect)
29 {
30         output_headers(1, 0, 0, 0, 1, 0);
31         do_template("aide_edituser_select");
32         end_burst();
33 }
34
35
36 typedef struct _UserListEntry {
37         int UID;
38         int AccessLevel;
39         int nLogons;
40         int nPosts;
41
42         StrBuf *UserName;
43         StrBuf *Passvoid;
44         time_t LastLogonT;
45         /* Just available for Single users to view: */
46         unsigned int Flags;
47         int DaysTillPurge;
48         int HasBio;
49 } UserListEntry;
50
51
52 UserListEntry* NewUserListOneEntry(StrBuf *SerializedUser, const char *Pos)
53 {
54         UserListEntry *ul;
55
56         if (StrLength(SerializedUser) < 8) 
57                 return NULL;
58
59         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
60         ul->UserName = NewStrBuf();
61         ul->Passvoid = NewStrBuf();
62
63         StrBufExtract_NextToken(ul->UserName,               SerializedUser, &Pos, '|');
64         StrBufExtract_NextToken(ul->Passvoid,               SerializedUser, &Pos, '|');
65         ul->Flags         = StrBufExtractNext_unsigned_long(SerializedUser, &Pos, '|');
66         ul->nLogons       = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
67         ul->nPosts        = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
68         ul->AccessLevel   = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
69         ul->UID           = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
70         ul->LastLogonT    = StrBufExtractNext_long(         SerializedUser, &Pos, '|');
71         ul->DaysTillPurge = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
72         return ul;
73 }
74
75 void DeleteUserListEntry(void *vUserList)
76 {
77         UserListEntry *ul = (UserListEntry*) vUserList;
78         if (!ul) return;
79         FreeStrBuf(&ul->UserName);
80         FreeStrBuf(&ul->Passvoid);
81         free(ul);
82 }
83
84 UserListEntry* NewUserListEntry(StrBuf *SerializedUserList)
85 {
86         const char *Pos = NULL;
87         UserListEntry *ul;
88
89         if (StrLength(SerializedUserList) < 8) 
90                 return NULL;
91
92         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
93         ul->UserName = NewStrBuf();
94         ul->Passvoid = NewStrBuf();
95
96         StrBufExtract_NextToken(ul->UserName,    SerializedUserList, &Pos, '|');
97         ul->AccessLevel = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
98         ul->UID         = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
99         ul->LastLogonT  = StrBufExtractNext_long(SerializedUserList, &Pos, '|');
100         ul->nLogons     = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
101         ul->nPosts      = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
102         StrBufExtract_NextToken(ul->Passvoid,    SerializedUserList, &Pos, '|');
103         ul->Flags = 0;
104         ul->HasBio = 0;
105         ul->DaysTillPurge = -1;
106         return ul;
107 }
108
109 /*
110  * Sort by Username
111  */
112 int CompareUserListName(const void *vUser1, const void *vUser2)
113 {
114         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
115         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
116
117         return strcmp(ChrPtr(u1->UserName), ChrPtr(u2->UserName));
118 }
119
120 int CompareUserListNameRev(const void *vUser1, const void *vUser2)
121 {
122         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
123         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
124         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
125 }
126
127 int GroupchangeUserListName(const void *vUser1, const void *vUser2)
128 {
129         UserListEntry *u1 = (UserListEntry*) vUser1;
130         UserListEntry *u2 = (UserListEntry*) vUser2;
131         return ChrPtr(u2->UserName)[0] != ChrPtr(u1->UserName)[0];
132 }
133
134 /*
135  * Sort by access level
136  */
137 int CompareAccessLevel(const void *vUser1, const void *vUser2)
138 {
139         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
140         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
141
142         return (u1->AccessLevel > u2->AccessLevel);
143 }
144
145 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
146 {
147         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
148         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
149
150         return (u2->AccessLevel > u1->AccessLevel);
151 }
152
153 int GroupchangeAccessLevel(const void *vUser1, const void *vUser2)
154 {
155         UserListEntry *u1 = (UserListEntry*) vUser1;
156         UserListEntry *u2 = (UserListEntry*) vUser2;
157
158         return u2->AccessLevel != u1->AccessLevel;
159 }
160
161 /*
162  * Sort by UID
163  */
164 int CompareUID(const void *vUser1, const void *vUser2)
165 {
166         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
167         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
168
169         return (u1->UID > u2->UID);
170 }
171
172 int CompareUIDRev(const void *vUser1, const void *vUser2)
173 {
174         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
175         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
176
177         return (u2->UID > u1->UID);
178 }
179
180 int GroupchangeUID(const void *vUser1, const void *vUser2)
181 {
182         UserListEntry *u1 = (UserListEntry*) vUser1;
183         UserListEntry *u2 = (UserListEntry*) vUser2;
184
185         return (u2->UID / 10) != (u1->UID / 10);
186 }
187
188 /*
189  * Sort By Date /// TODO!
190  */
191 int CompareLastLogon(const void *vUser1, const void *vUser2)
192 {
193         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
194         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
195
196         return (u1->LastLogonT > u2->LastLogonT);
197 }
198
199 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
200 {
201         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
202         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
203
204         return (u2->LastLogonT > u1->LastLogonT);
205 }
206
207 int GroupchangeLastLogon(const void *vUser1, const void *vUser2)
208 {
209         UserListEntry *u1 = (UserListEntry*) vUser1;
210         UserListEntry *u2 = (UserListEntry*) vUser2;
211
212         return (u2->LastLogonT != u1->LastLogonT);
213 }
214
215 /*
216  * Sort By Number of Logons
217  */
218 int ComparenLogons(const void *vUser1, const void *vUser2)
219 {
220         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
221         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
222
223         return (u1->nLogons > u2->nLogons);
224 }
225
226 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
227 {
228         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
229         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
230
231         return (u2->nLogons > u1->nLogons);
232 }
233
234 int GroupchangenLogons(const void *vUser1, const void *vUser2)
235 {
236         UserListEntry *u1 = (UserListEntry*) vUser1;
237         UserListEntry *u2 = (UserListEntry*) vUser2;
238
239         return (u2->nLogons / 100) != (u1->nLogons / 100);
240 }
241
242 /*
243  * Sort By Number of Posts
244  */
245 int ComparenPosts(const void *vUser1, const void *vUser2)
246 {
247         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
248         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
249
250         return (u1->nPosts > u2->nPosts);
251 }
252
253 int ComparenPostsRev(const void *vUser1, const void *vUser2)
254 {
255         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
256         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
257
258         return (u2->nPosts > u1->nPosts);
259 }
260
261 int GroupchangenPosts(const void *vUser1, const void *vUser2)
262 {
263         UserListEntry *u1 = (UserListEntry*) vUser1;
264         UserListEntry *u2 = (UserListEntry*) vUser2;
265
266         return (u2->nPosts / 100) != (u1->nPosts / 100);
267 }
268
269
270 HashList *iterate_load_userlist(StrBuf *Target, WCTemplputParams *TP)
271 {
272         int Done = 0;
273         CompareFunc SortIt;
274         HashList *Hash = NULL;
275         StrBuf *Buf;
276         UserListEntry* ul;
277         int len;
278         int UID;
279         void *vData;
280         WCTemplputParams SubTP;
281
282         memset(&SubTP, 0, sizeof(WCTemplputParams));    
283         serv_puts("LIST");
284         Buf = NewStrBuf();
285         StrBuf_ServGetln(Buf);
286         if (GetServerStatus(Buf, NULL) == 1) {
287                 Hash = NewHash(1, Flathash);
288
289                 while (!Done) {
290                         len = StrBuf_ServGetln(Buf);
291                         if ((len <0) || 
292                             ((len == 3) &&
293                              !strcmp(ChrPtr(Buf), "000")))
294                         {
295                                 Done = 1;
296                                 break;
297                         }
298                         ul = NewUserListEntry(Buf);
299                         if (ul == NULL)
300                                 continue;
301
302                         Put(Hash, IKEY(ul->UID), ul, DeleteUserListEntry); 
303                 }
304
305                 serv_puts("LBIO 1");
306                 StrBuf_ServGetln(Buf);
307                 if (GetServerStatus(Buf, NULL) == 1)
308                         Done = 0;
309                         while (!Done) {
310                         len = StrBuf_ServGetln(Buf);
311                         if ((len <0) || 
312                             ((len == 3) &&
313                              !strcmp(ChrPtr(Buf), "000")))
314                         {
315                                 Done = 1;
316                                 break;
317                         }
318                         UID = atoi(ChrPtr(Buf));
319                         if (GetHash(Hash, IKEY(UID), &vData) && vData != 0)
320                         {
321                                 ul = (UserListEntry*)vData;
322                                 ul->HasBio = 1;
323                         }
324                 }
325                 SubTP.Filter.ContextType = CTX_USERLIST;
326                 SortIt = RetrieveSort(&SubTP, HKEY("USER"), HKEY("user:uid"), 0);
327                 if (SortIt != NULL)
328                         SortByPayload(Hash, SortIt);
329                 else 
330                         SortByPayload(Hash, CompareUID);
331         }
332         FreeStrBuf(&Buf);
333         return Hash;
334 }
335
336
337 void tmplput_USERLIST_UserName(StrBuf *Target, WCTemplputParams *TP)
338 {
339         UserListEntry *ul = (UserListEntry*) CTX;
340         StrBufAppendTemplate(Target, TP, ul->UserName, 0);
341 }
342
343 void tmplput_USERLIST_Password(StrBuf *Target, WCTemplputParams *TP)
344 {
345         UserListEntry *ul = (UserListEntry*) CTX;
346         StrBufAppendTemplate(Target, TP, ul->Passvoid, 0);
347 }
348
349 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, WCTemplputParams *TP)
350 {
351         UserListEntry *ul = (UserListEntry*) CTX;
352
353         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
354 }
355
356 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, WCTemplputParams *TP)
357 {
358         UserListEntry *ul = (UserListEntry*) CTX;
359         
360         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
361 }
362
363 void tmplput_USERLIST_UID(StrBuf *Target, WCTemplputParams *TP)
364 {
365         UserListEntry *ul = (UserListEntry*) CTX;
366
367         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
368 }
369
370 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, WCTemplputParams *TP)
371 {
372         UserListEntry *ul = (UserListEntry*) CTX;
373
374         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
375 }
376 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, WCTemplputParams *TP)
377 {
378         UserListEntry *ul = (UserListEntry*) CTX;
379         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
380 }
381
382 void tmplput_USERLIST_nLogons(StrBuf *Target, WCTemplputParams *TP)
383 {
384         UserListEntry *ul = (UserListEntry*) CTX;
385
386         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
387 }
388
389 void tmplput_USERLIST_nPosts(StrBuf *Target, WCTemplputParams *TP)
390 {
391         UserListEntry *ul = (UserListEntry*) CTX;
392
393         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
394 }
395
396 void tmplput_USERLIST_Flags(StrBuf *Target, WCTemplputParams *TP)
397 {
398         UserListEntry *ul = (UserListEntry*) CTX;
399
400         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
401 }
402
403 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, WCTemplputParams *TP)
404 {
405         UserListEntry *ul = (UserListEntry*) CTX;
406
407         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
408 }
409
410 int ConditionalUser(StrBuf *Target, WCTemplputParams *TP)
411 {
412         UserListEntry *ul = (UserListEntry*) CTX;
413         if (havebstr("usernum")) {
414                 return ibstr("usernum") == ul->UID;
415         }
416         else if (havebstr("username")) {
417                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
418         }
419         else 
420                 return 0;
421 }
422
423 int ConditionalFlagINetEmail(StrBuf *Target, WCTemplputParams *TP)
424 {
425         UserListEntry *ul = (UserListEntry*) CTX;
426         return (ul->Flags & US_INTERNET) != 0;
427 }
428
429 int ConditionalUserAccess(StrBuf *Target, WCTemplputParams *TP)
430 {
431         UserListEntry *ul = (UserListEntry*) CTX;
432         
433         if (ul == NULL)
434                 return 0;
435
436         return GetTemplateTokenNumber(Target, 
437                                       TP, 
438                                       3, 
439                                       AxNewU)
440                 ==
441                 ul->AccessLevel;
442 }
443 int ConditionalHaveBIO(StrBuf *Target, WCTemplputParams *TP)
444 {
445         UserListEntry *ul = (UserListEntry*) CTX;
446         
447         if (ul == NULL)
448                 return 0;
449         return ul->HasBio;
450 }
451
452 void tmplput_USER_BIO(StrBuf *Target, WCTemplputParams *TP)
453 {
454         int Done = 0;
455         StrBuf *Buf;
456         const char *who;
457         long len;
458
459         GetTemplateTokenString(Target, TP, 0, &who, &len);
460
461         Buf = NewStrBuf();
462         serv_printf("RBIO %s", who);
463         StrBuf_ServGetln(Buf);
464         if (GetServerStatus(Buf, NULL) == 1) {
465                 StrBuf *BioBuf = NewStrBufPlain(NULL, SIZ);
466                 while (!Done && StrBuf_ServGetln(Buf)>=0) {
467                         if ( (StrLength(Buf)==3) && 
468                              !strcmp(ChrPtr(Buf), "000")) 
469                                 Done = 1;
470                         else
471                                 StrBufAppendBuf(BioBuf, Buf, 0);
472                 }
473                 StrBufAppendTemplate(Target, TP, BioBuf, 1);
474                 FreeStrBuf(&BioBuf);
475         }
476         FreeStrBuf(&Buf);
477 }
478
479 int Conditional_USER_HAS_PIC(StrBuf *Target, WCTemplputParams *TP)
480 {
481         StrBuf *Buf;
482         const char *who;
483         long len;
484
485         GetTemplateTokenString(Target, TP, 2, &who, &len);
486
487         Buf = NewStrBuf();
488         serv_printf("OIMG _userpic_|%s", who);
489         StrBuf_ServGetln(Buf);
490         if (GetServerStatus(Buf, NULL) != 2) {
491                 serv_puts("CLOS");
492                 StrBuf_ServGetln(Buf);
493                 GetServerStatus(Buf, NULL);
494                 FreeStrBuf(&Buf);
495                 return 1;
496         } else {
497                 FreeStrBuf(&Buf);
498                 return 0;
499         }
500 }
501
502
503 /*
504  *  Locate the message number of a user's vCard in the current room
505  *  Returns the message id of his vcard
506  */
507 long locate_user_vcard_in_this_room(message_summary **VCMsg, wc_mime_attachment **VCAtt)
508 {
509         wcsession *WCC = WC;
510         HashPos *at;
511         HashPos *att;
512         const char *HashKey;
513         long HKLen;
514         void *vMsg;
515         message_summary *Msg;
516         wc_mime_attachment *Att;
517         StrBuf *Buf;
518         long vcard_msgnum = (-1L);
519         int already_tried_creating_one = 0;
520         StrBuf *FoundCharset = NewStrBuf();
521         StrBuf *Error = NULL;
522         SharedMessageStatus Stat;
523
524
525         Buf = NewStrBuf();
526 TRYAGAIN:
527         memset(&Stat, 0, sizeof(SharedMessageStatus));
528         Stat.maxload = 10000;
529         Stat.lowest_found = (-1);
530         Stat.highest_found = (-1);
531         /* Search for the user's vCard */
532         if (load_msg_ptrs("MSGS ALL||||1", &Stat, NULL) > 0) {
533                 at = GetNewHashPos(WCC->summ, 0);
534                 while (GetNextHashPos(WCC->summ, at, &HKLen, &HashKey, &vMsg)) {
535                         Msg = (message_summary*) vMsg;          
536                         Msg->MsgBody =  (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
537                         memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment));
538                         Msg->MsgBody->msgnum = Msg->msgnum;
539
540                         load_message(Msg, FoundCharset, &Error);
541                         
542                         if (Msg->AllAttach != NULL) {
543                                 att = GetNewHashPos(Msg->AllAttach, 0);
544                                 while (GetNextHashPos(Msg->AllAttach, att, &HKLen, &HashKey, &vMsg) && 
545                                        (vcard_msgnum == -1)) {
546                                         Att = (wc_mime_attachment*) vMsg;
547                                         if (
548                                                 (strcasecmp(ChrPtr(Att->ContentType), "text/x-vcard") == 0)
549                                                 || (strcasecmp(ChrPtr(Att->ContentType), "text/vcard") == 0)
550                                         ) {
551                                                 *VCAtt = Att;
552                                                 *VCMsg = Msg;
553                                                 vcard_msgnum = Msg->msgnum;
554                                                 if (Att->Data == NULL) {
555                                                         MimeLoadData(Att);
556                                                 }
557                                         }
558                                 }
559                                 DeleteHashPos(&att);
560                         }
561                         FreeStrBuf(&Error);     /* don't care... */
562                         
563                 }
564                 DeleteHashPos(&at);             
565         }
566
567         /* If there's no vcard, create one */
568         if ((*VCMsg == NULL) && (already_tried_creating_one == 0)) {
569                 FlushStrBuf(Buf);
570                 already_tried_creating_one = 1;
571                 serv_puts("ENT0 1|||4");
572                 StrBuf_ServGetln(Buf);
573                 if (GetServerStatus(Buf, NULL) == 4) {
574                         serv_puts("Content-type: text/x-vcard");
575                         serv_puts("");
576                         serv_puts("begin:vcard");
577                         serv_puts("end:vcard");
578                         serv_puts("000");
579                 }
580                 else 
581                         syslog(1, "Error while creating user vcard: %s\n", ChrPtr(Buf));
582                 goto TRYAGAIN;
583         }
584         FreeStrBuf(&Buf);
585         FreeStrBuf(&FoundCharset);
586
587         return(vcard_msgnum);
588 }
589
590
591 /*
592  *  Display the form for editing a user's address book entry
593  *  username the name of the user
594  *  usernum the citadel-uid of the user
595  */
596 void display_edit_address_book_entry(const char *username, long usernum) {
597         message_summary *VCMsg = NULL;
598         wc_mime_attachment *VCAtt = NULL;
599         StrBuf *roomname;
600         StrBuf *Buf;
601         long vcard_msgnum = (-1L);
602
603         /* Locate the user's config room, creating it if necessary */
604         Buf = NewStrBuf();
605         roomname = NewStrBuf();
606         StrBufPrintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
607         serv_printf("GOTO %s||1", ChrPtr(roomname));
608         StrBuf_ServGetln(Buf);
609         if (GetServerStatus(Buf, NULL) != 2) {
610                 serv_printf("CRE8 1|%s|5|||1|", ChrPtr(roomname));
611                 StrBuf_ServGetln(Buf);
612                 GetServerStatus(Buf, NULL);
613                 serv_printf("GOTO %s||1", ChrPtr(roomname));
614                 StrBuf_ServGetln(Buf);
615                 if (GetServerStatusMsg(Buf, NULL, 1, 2) != 2) {
616                         select_user_to_edit(username);
617                         FreeStrBuf(&Buf);
618                         FreeStrBuf(&roomname);
619                         return;
620                 }
621         }
622         FreeStrBuf(&Buf);
623
624         locate_user_vcard_in_this_room(&VCMsg, &VCAtt);
625
626         if (VCMsg == NULL) {
627                 AppendImportantMessage(_("An error occurred while trying to create or edit this address book entry."), -1);
628                 select_user_to_edit(username);
629                 FreeStrBuf(&roomname);
630                 return;
631         }
632
633         do_edit_vcard(vcard_msgnum, "1", 
634                       VCMsg,
635                       VCAtt,
636                       "select_user_to_edit", 
637                       ChrPtr(roomname));
638         FreeStrBuf(&roomname);
639 }
640
641 /*
642  *  burge a user 
643  *  username the name of the user to remove
644  */
645 void delete_user(char *username) {
646         StrBuf *Buf;
647         
648         Buf = NewStrBuf();
649         serv_printf("ASUP %s|0|0|0|0|0|", username);
650         StrBuf_ServGetln(Buf);
651         GetServerStatusMsg(Buf, NULL, 1, 2);
652
653         select_user_to_edit( bstr("username"));
654         FreeStrBuf(&Buf);
655 }
656                 
657
658 void display_edituser(const char *supplied_username, int is_new) {
659         const char *Pos;
660         UserListEntry* UL;
661         StrBuf *Buf;
662         char username[256];
663
664         if (supplied_username != NULL) {
665                 safestrncpy(username, supplied_username, sizeof username);
666         }
667         else {
668                 safestrncpy(username, bstr("username"), sizeof username);
669         }
670
671         Buf = NewStrBuf();
672         serv_printf("AGUP %s", username);
673         StrBuf_ServGetln(Buf);
674         if (GetServerStatusMsg(Buf, NULL, 1, 2) != 2) {
675                 select_user_to_edit(username);
676                 FreeStrBuf(&Buf);
677                 return;
678         }
679         else {
680                 Pos = ChrPtr(Buf) + 4;
681                 UL = NewUserListOneEntry(Buf, Pos);
682                 if ((UL != NULL) && havebstr("edit_abe_button")) {
683                         display_edit_address_book_entry(username, UL->UID);
684                 }
685                 else if ((UL != NULL) && havebstr("delete_button")) {
686                         delete_user(username);
687                 }
688                 else if (UL != NULL) {
689                         WCTemplputParams SubTP;
690                         memset(&SubTP, 0, sizeof(WCTemplputParams));
691                         SubTP.Filter.ContextType = CTX_USERLIST;
692                         SubTP.Context = UL;
693                         output_headers(1, 0, 0, 0, 1, 0);
694                         DoTemplate(HKEY("aide_edituser_detailview"), NULL, &SubTP);
695                         end_burst();
696                 }
697                 DeleteUserListEntry(UL);
698                 
699         }
700         FreeStrBuf(&Buf);
701 }
702
703 /*
704  *  do the backend operation of the user edit on the server
705  */
706 void edituser(void) {
707         int is_new = 0;
708         unsigned int flags = 0;
709         const char *username;
710
711         is_new = ibstr("is_new");
712         username = bstr("username");
713
714         if (!havebstr("ok_button")) {
715                 AppendImportantMessage(_("Changes were not saved."), -1);
716         }       
717         else {
718                 StrBuf *Buf = NewStrBuf();
719
720                 flags = ibstr("flags");
721                 if (yesbstr("inetmail")) {
722                         flags |= US_INTERNET;
723                 }
724                 else {
725                         flags &= ~US_INTERNET ;
726                 }
727
728                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
729                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
730                         StrBuf_ServGetln(Buf);
731                         if (GetServerStatusMsg(Buf, NULL, 1, 2) != 2) {
732                                 username = bstr("newname");
733                         }
734                 }
735
736                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
737                         username,
738                         bstr("password"),
739                         flags,
740                         bstr("timescalled"),
741                         bstr("msgsposted"),
742                         bstr("axlevel"),
743                         bstr("usernum"),
744                         bstr("lastcall"),
745                         bstr("purgedays")
746                 );
747                 StrBuf_ServGetln(Buf);
748                 GetServerStatusMsg(Buf, NULL, 1, 2);
749                 FreeStrBuf(&Buf);
750         }
751
752         /*
753          * If we are in the middle of creating a new user, move on to
754          * the vCard edit screen.
755          */
756         if (is_new) {
757                 display_edit_address_book_entry(username, lbstr("usernum") );
758         }
759         else {
760                 select_user_to_edit(username);
761         }
762 }
763
764
765
766 /*
767  *  create a new user
768  * take the web environment username and create it on the citadel server
769  */
770 void create_user(void) {
771         long FullState;
772         StrBuf *Buf;
773         const char *username;
774
775         Buf = NewStrBuf();
776         username = bstr("username");
777         serv_printf("CREU %s", username);
778         StrBuf_ServGetln(Buf);
779         if (GetServerStatus(Buf, &FullState) == 2) {
780                 AppendImportantMessage(_("A new user has been created."), -1);
781                 display_edituser(username, 1);
782         }
783         else if (FullState == 570) {
784                 AppendImportantMessage(_("You are attempting to create a new user from within Citadel "
785                                          "while running in host based authentication mode.  In this mode, "
786                                          "you must create new users on the host system, not within Citadel."), 
787                                        -1);
788                 select_user_to_edit(NULL);
789         }
790         else {
791                 AppendImportantMessage(ChrPtr(Buf) + 4, StrLength(Buf) - 4);
792                 select_user_to_edit(NULL);
793         }
794         FreeStrBuf(&Buf);
795 }
796
797
798 void _select_user_to_edit(void) {
799         select_user_to_edit(NULL);
800 }
801
802
803 void _display_edituser(void) {
804         display_edituser(NULL, 0);
805 }
806
807 void showuser(void)
808 {
809         output_headers(1, 0, 0, 0, 1, 0);
810         do_template("user_show");
811         end_burst();
812 }
813
814
815 void 
816 InitModule_USEREDIT
817 (void)
818 {
819         WebcitAddUrlHandler(HKEY("showuser"), "", 0, showuser, 0);
820         WebcitAddUrlHandler(HKEY("select_user_to_edit"), "", 0, _select_user_to_edit, 0);
821         WebcitAddUrlHandler(HKEY("display_edituser"), "", 0, _display_edituser, 0);
822         WebcitAddUrlHandler(HKEY("edituser"), "", 0, edituser, 0);
823         WebcitAddUrlHandler(HKEY("create_user"), "", 0, create_user, 0);
824
825         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, NULL, CTX_USERLIST);
826         RegisterNamespace("USERLIST:PASSWD",        0, 1, tmplput_USERLIST_Password, NULL, CTX_USERLIST);
827         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, NULL, CTX_USERLIST);
828         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, NULL, CTX_USERLIST);
829         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, NULL, CTX_USERLIST);
830         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, NULL, CTX_USERLIST);
831         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, NULL, CTX_USERLIST);
832         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, NULL, CTX_USERLIST);
833         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, NULL, CTX_USERLIST);
834                                                     
835         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, NULL, CTX_USERLIST);
836         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, NULL, CTX_USERLIST);
837
838         RegisterNamespace("USER:BIO", 1, 2, tmplput_USER_BIO,  NULL, CTX_NONE);
839
840         RegisterConditional(HKEY("COND:USERNAME"),  0,    ConditionalUser, CTX_USERLIST);
841         RegisterConditional(HKEY("COND:USERACCESS"), 0,   ConditionalUserAccess, CTX_USERLIST);
842         RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST);
843         RegisterConditional(HKEY("COND:USERLIST:HAVEBIO"), 0, ConditionalHaveBIO, CTX_USERLIST);
844
845         RegisterConditional(HKEY("COND:USER:PIC"), 1, Conditional_USER_HAS_PIC,  CTX_NONE);
846
847         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
848         
849
850
851         RegisterSortFunc(HKEY("user:name"),
852                          HKEY("userlist"),
853                          CompareUserListName,
854                          CompareUserListNameRev,
855                          GroupchangeUserListName,
856                          CTX_USERLIST);
857         RegisterSortFunc(HKEY("user:accslvl"),
858                          HKEY("userlist"),
859                          CompareAccessLevel,
860                          CompareAccessLevelRev,
861                          GroupchangeAccessLevel,
862                          CTX_USERLIST);
863
864         RegisterSortFunc(HKEY("user:nlogons"),
865                          HKEY("userlist"),
866                          ComparenLogons,
867                          ComparenLogonsRev,
868                          GroupchangenLogons,
869                          CTX_USERLIST);
870
871         RegisterSortFunc(HKEY("user:uid"),
872                          HKEY("userlist"),
873                          CompareUID,
874                          CompareUIDRev,
875                          GroupchangeUID,
876                          CTX_USERLIST);
877
878         RegisterSortFunc(HKEY("user:lastlogon"),
879                          HKEY("userlist"),
880                          CompareLastLogon,
881                          CompareLastLogonRev,
882                          GroupchangeLastLogon,
883                          CTX_USERLIST);
884
885         RegisterSortFunc(HKEY("user:nmsgposts"),
886                          HKEY("userlist"),
887                          ComparenPosts,
888                          ComparenPostsRev,
889                          GroupchangenPosts,
890                          CTX_USERLIST);
891
892         REGISTERTokenParamDefine(AxDeleted);
893         REGISTERTokenParamDefine(AxNewU);
894         REGISTERTokenParamDefine(AxProbU);
895         REGISTERTokenParamDefine(AxLocU);
896         REGISTERTokenParamDefine(AxNetU);
897         REGISTERTokenParamDefine(AxPrefU);
898         REGISTERTokenParamDefine(AxAideU);
899 }
900