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