Răsfoiți Sursa

* Now using EncryptedStream to write/save userfiles

svn: 2942
Bryan Drewery 20 ani în urmă
părinte
comite
3bcb4da46f

+ 6 - 6
src/mod/channels.mod/channels.h

@@ -31,11 +31,11 @@ void set_handle_chaninfo(struct userrec *, char *, char *, char *);
 struct chanuserrec *get_chanrec(struct userrec *u, char *);
 struct chanuserrec *add_chanrec(struct userrec *u, char *);
 void del_chanrec(struct userrec *, char *);
-bool write_bans(FILE *, int);
-bool write_exempts (FILE *, int);
-bool write_chans (FILE *, int);
-bool write_chans_compat (FILE *, int);
-bool write_invites (FILE *, int);
+void write_bans(Stream&, int);
+void write_exempts(Stream&, int);
+void write_chans(Stream&, int);
+void write_chans_compat(Stream&, int);
+void write_invites(Stream&, int);
 bool expired_mask(struct chanset_t *, char *);
 void set_handle_laston(char *, struct userrec *, time_t);
 int u_delmask(char type, struct chanset_t *c, char *who, int doit);
@@ -51,7 +51,7 @@ bool u_match_mask(struct maskrec *, char *);
 bool ismasked(masklist *, const char *);
 bool ismodeline(masklist *, const char *);
 void channels_report(int, int);
-void channels_writeuserfile(bool = 0);
+void channels_writeuserfile(Stream&, bool = 0);
 void rcmd_chans(char *, char *, char *);
 
 extern char		glob_chanset[512];

+ 59 - 105
src/mod/channels.mod/userchan.c

@@ -24,6 +24,7 @@
  */
 
 
+#include "src/Stream.h"
 extern struct cmd_pass *cmdpass;
 
 struct chanuserrec *get_chanrec(struct userrec *u, char *chname)
@@ -568,168 +569,137 @@ static void tell_masks(const char type, int idx, bool show_inact, char *match, b
 
 /* Write the ban lists and the ignore list to a file.
  */
-bool write_bans(FILE *f, int idx)
+void write_bans(Stream& stream, int idx)
 {
   if (global_ign)
-    if (lfprintf(f, IGNORE_NAME " - -\n") == EOF)	/* Daemus */
-      return 0;
+    stream.printf(IGNORE_NAME " - -\n");
 
   char *mask = NULL;
 
   for (struct igrec *i = global_ign; i; i = i->next) {
     mask = str_escape(i->igmask, ':', '\\');
-    if (!mask ||
-	lfprintf(f, "- %s:%s%li:%s:%li:%s\n", mask,
+    if (mask) {
+	stream.printf("- %s:%s%li:%s:%li:%s\n", mask,
 		(i->flags & IGREC_PERM) ? "+" : "", (long) i->expire,
 		i->user ? i->user : conf.bot->nick, (long) i->added,
-		i->msg ? i->msg : "") == EOF) {
-      if (mask)
-	free(mask);
-      return 0;
+		i->msg ? i->msg : "");
+        free(mask);
     }
-    free(mask);
   }
   if (global_bans)
-    if (lfprintf(f, BAN_NAME " - -\n") == EOF)	/* Daemus */
-      return 0;
+    stream.printf(BAN_NAME " - -\n");
 
   maskrec *b = NULL;
 
   for (b = global_bans; b; b = b->next) {
     mask = str_escape(b->mask, ':', '\\');
-    if (!mask ||
-	lfprintf(f, "- %s:%s%li%s:+%li:%li:%s:%s\n", mask,
+    if (mask) {
+	stream.printf("- %s:%s%li%s:+%li:%li:%s:%s\n", mask,
 		(b->flags & MASKREC_PERM) ? "+" : "", (long) b->expire,
 		(b->flags & MASKREC_STICKY) ? "*" : "", (long) b->added,
 		(long) b->lastactive, b->user ? b->user : conf.bot->nick,
-		b->desc ? b->desc : "requested") == EOF) {
-      if (mask)
-	free(mask);
-      return 0;
+		b->desc ? b->desc : "requested");
+      free(mask);
     }
-    free(mask);
   }
   for (struct chanset_t *chan = chanset; chan; chan = chan->next) {
-    if (lfprintf(f, "::%s bans\n", chan->dname) == EOF)
-      return 0;
+    stream.printf("::%s bans\n", chan->dname);
+
     for (b = chan->bans; b; b = b->next) {
       mask = str_escape(b->mask, ':', '\\');
-      if (!mask ||
-        lfprintf(f, "- %s:%s%li%s:+%li:%li:%s:%s\n", mask,
+      if (mask) {
+        stream.printf("- %s:%s%li%s:+%li:%li:%s:%s\n", mask,
 	        (b->flags & MASKREC_PERM) ? "+" : "", (long) b->expire,
 	        (b->flags & MASKREC_STICKY) ? "*" : "", (long) b->added,
 	        (long) b->lastactive, b->user ? b->user : conf.bot->nick,
-	        b->desc ? b->desc : "requested") == EOF) {
-          if (mask)
-            free(mask);
-          return 0;
-        }
-      free(mask);
+	        b->desc ? b->desc : "requested");
+        free(mask);
+      }
     }
   }
-  return 1;
 }
 /* Write the exemptlists to a file.
  */
-bool write_exempts(FILE *f, int idx)
+void write_exempts(Stream& stream, int idx)
 {
   if (global_exempts)
-    if (lfprintf(f, EXEMPT_NAME " - -\n") == EOF) /* Daemus */
-      return 0;
+    stream.printf(EXEMPT_NAME " - -\n");
 
   maskrec *e = NULL;
   char *mask = NULL;
 
   for (e = global_exempts; e; e = e->next) {
     mask = str_escape(e->mask, ':', '\\');
-    if (!mask ||
-        lfprintf(f, "%s %s:%s%li%s:+%li:%li:%s:%s\n", "%", mask,
+    if (mask) {
+        stream.printf("%s %s:%s%li%s:+%li:%li:%s:%s\n", "%", mask,
 		(e->flags & MASKREC_PERM) ? "+" : "", (long) e->expire,
 		(e->flags & MASKREC_STICKY) ? "*" : "", (long) e->added,
 		(long) e->lastactive, e->user ? e->user : conf.bot->nick,
-		e->desc ? e->desc : "requested") == EOF) {
-      if (mask)
-	free(mask);
-      return 0;
+		e->desc ? e->desc : "requested");
+      free(mask);
     }
-    free(mask);
   }
   for (struct chanset_t *chan = chanset;chan ;chan = chan->next) {
-    if (lfprintf(f, "&&%s exempts\n", chan->dname) == EOF)
-      return 0;
+    stream.printf("&&%s exempts\n", chan->dname);
     for (e = chan->exempts; e; e = e->next) {
       mask = str_escape(e->mask, ':', '\\');
-      if (!mask ||
-		lfprintf(f,"%s %s:%s%li%s:+%li:%li:%s:%s\n","%", mask,
+      if (mask) {
+	stream.printf("%s %s:%s%li%s:+%li:%li:%s:%s\n","%", mask,
 		(e->flags & MASKREC_PERM) ? "+" : "", (long) e->expire,
 		(e->flags & MASKREC_STICKY) ? "*" : "", (long) e->added,
 		(long) e->lastactive, e->user ? e->user : conf.bot->nick,
-		e->desc ? e->desc : "requested") == EOF) {
-        if (mask)
-           free(mask);
-         return 0;
+		e->desc ? e->desc : "requested");
+        free(mask);
       }
-      free(mask);
     }
   }
-  return 1;
 }
 
 /* Write the invitelists to a file.
  */
-bool write_invites(FILE *f, int idx)
+void write_invites(Stream& stream, int idx)
 {
-
   if (global_invites)
-    if (lfprintf(f, INVITE_NAME " - -\n") == EOF) /* Daemus */
-      return 0;
+    stream.printf(INVITE_NAME " - -\n");
 
   maskrec *ir = NULL;
   char *mask = NULL;
 
   for (ir = global_invites; ir; ir = ir->next)  {
     mask = str_escape(ir->mask, ':', '\\');
-    if (!mask ||
-	lfprintf(f,"@ %s:%s%li%s:+%li:%li:%s:%s\n", mask,
+    if (mask) {
+      stream.printf("@ %s:%s%li%s:+%li:%li:%s:%s\n", mask,
 		(ir->flags & MASKREC_PERM) ? "+" : "", (long) ir->expire,
 		(ir->flags & MASKREC_STICKY) ? "*" : "", (long) ir->added,
 		(long) ir->lastactive, ir->user ? ir->user : conf.bot->nick,
-		ir->desc ? ir->desc : "requested") == EOF) {
-      if (mask)
-	free(mask);
-      return 0;
+		ir->desc ? ir->desc : "requested");
+      free(mask);
     }
-    free(mask);
   }
   for (struct chanset_t *chan = chanset; chan; chan = chan->next) {
-    if (lfprintf(f, "$$%s invites\n", chan->dname) == EOF)
-      return 0;
+    stream.printf("$$%s invites\n", chan->dname);
+
     for (ir = chan->invites; ir; ir = ir->next) {
       mask = str_escape(ir->mask, ':', '\\');
-      if (!mask ||
-	      lfprintf(f,"@ %s:%s%li%s:+%li:%li:%s:%s\n", mask,
+      if (mask) {
+        stream.printf("@ %s:%s%li%s:+%li:%li:%s:%s\n", mask,
 		      (ir->flags & MASKREC_PERM) ? "+" : "", (long) ir->expire,
 		      (ir->flags & MASKREC_STICKY) ? "*" : "", (long) ir->added,
 		      (long) ir->lastactive, ir->user ? ir->user : conf.bot->nick,
-		      ir->desc ? ir->desc : "requested") == EOF) {
-        if (mask)
-	  free(mask);
-	return 0;
+		      ir->desc ? ir->desc : "requested");
+        free(mask);
       }
-      free(mask);
     }
   }
-  return 1;
 }
 
 /* Write the channels to the userfile
  */
-bool write_chans(FILE *f, int idx)
+void write_chans(Stream& stream, int idx)
 {
   putlog(LOG_DEBUG, "*", "Writing channels..");
 
-  if (lfprintf(f, CHANS_NAME " - -\n") == EOF) /* Daemus */
-    return 0;
+  stream.printf(CHANS_NAME " - -\n");
 
   char w[1024] = "";
 
@@ -746,7 +716,7 @@ bool write_chans(FILE *f, int idx)
     else
       inactive = PLSMNS(channel_inactive(chan));
 
-    if (lfprintf(f, "\
+    stream.printf("\
 + channel add %s { chanmode { %s } addedby %s addedts %li \
 bad-cookie %d manop %d mdop %d mop %d limit %d \
 flood-chan %d:%d flood-ctcp %d:%d flood-join %d:%d \
@@ -819,21 +789,18 @@ flood-exempt %d flood-lock-time %d \
  * also include a %ctemp above.
  *      PLSMNS(channel_temp(chan)),
  */
-        ) == EOF)
-          return 0;
+    );
   }
-  return 1;
 }
 
 /* FIXME: remove after 1.2.14 */
 /* Write the channels to the userfile
  */
-bool write_chans_compat(FILE *f, int idx)
+void write_chans_compat(Stream& stream, int idx)
 {
   putlog(LOG_DEBUG, "*", "Writing channels..");
 
-  if (lfprintf(f, CHANS_NAME " - -\n") == EOF) /* Daemus */
-    return 0;
+  stream.printf(CHANS_NAME " - -\n");
 
   char w[1024] = "";
 
@@ -850,7 +817,7 @@ bool write_chans_compat(FILE *f, int idx)
     else
       inactive = PLSMNS(channel_inactive(chan));
 
-    if (lfprintf(f, "\
+    stream.printf("\
 + channel add %s { chanmode { %s } addedby %s addedts %li \
 bad-cookie %d manop %d mdop %d mop %d limit %d \
 flood-chan %d:%d flood-ctcp %d:%d flood-join %d:%d \
@@ -918,34 +885,21 @@ exempt-time %d invite-time %d voice-non-ident %d auto-delay %d \
  * also include a %ctemp above.
  *      PLSMNS(channel_temp(chan)),
  */
-        ) == EOF)
-          return 0;
+    );
   }
-  return 1;
 }
 
-void channels_writeuserfile(bool old)
+void channels_writeuserfile(Stream& stream, bool old)
 {
-  char s[1024] = "";
-  FILE *f = NULL;
-  int  ret = 0;
-
   putlog(LOG_DEBUG, "@", "Writing channel/ban/exempt/invite entries.");
-  simple_snprintf(s, sizeof(s), "%s~new", userfile);
-  f = fopen(s, "a");
-  if (f) {
-    if (!old)
-      ret  = write_chans(f, -1);
-    else
-      ret  = write_chans_compat(f, -1);
-    ret += write_vars_and_cmdpass(f, -1);
-    ret += write_bans(f, -1);
-    ret += write_exempts(f, -1);
-    ret += write_invites(f, -1);
-    fclose(f);
-  }
-  if (ret < 5)
-    putlog(LOG_MISC, "*", "ERROR writing user file.");
+  if (!old)
+    write_chans(stream, -1);
+  else
+    write_chans_compat(stream -1);
+  write_vars_and_cmdpass(stream, -1);
+  write_bans(stream, -1);
+  write_exempts(stream, -1);
+  write_invites(stream, -1);
 }
 
 /* Expire mask originally set by `who' on `chan'?

+ 6 - 7
src/mod/console.mod/console.c

@@ -39,6 +39,7 @@
 #include "src/users.h"
 #include "src/misc.h"
 #include "src/core_binds.h"
+#include "src/Stream.h"
 
 struct console_info {
   char *channel;
@@ -99,20 +100,18 @@ console_kill(struct user_entry *e)
   return 1;
 }
 
-static bool
-console_write_userfile(FILE * f, struct userrec *u, struct user_entry *e, int idx)
+static void
+console_write_userfile(Stream& stream, const struct userrec *u, const struct user_entry *e, int idx)
 {
   if (u->bot)
-    return 1;
+    return;
 
   struct console_info *i = (struct console_info *) e->u.extra;
 
-  if (lfprintf(f, "--CONSOLE %s %s %s %d %d %d %d %d %d %d %d\n",
+  stream.printf("--CONSOLE %s %s %s %d %d %d %d %d %d %d %d\n",
                i->channel, masktype(i->conflags),
                stripmasktype(i->stripflags), i->echoflags,
-               i->page, i->conchan, i->color, i->banner, i->channels, i->bots, i->whom) == EOF)
-    return 0;
-  return 1;
+               i->page, i->conchan, i->color, i->banner, i->channels, i->bots, i->whom);
 }
 
 static bool

+ 7 - 19
src/mod/share.mod/share.c

@@ -37,6 +37,7 @@
 #include "src/botnet.h"
 #include "src/auth.h"
 #include "src/set.h"
+#include "src/EncryptedStream.h"
 
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -1206,10 +1207,9 @@ static bool
 write_tmp_userfile(char *fn, const struct userrec *bu, int idx)
 {
   FILE *f = NULL;
-  int ok = 0;
+  int ok = 1;
 
   if ((f = fopen(fn, "wb"))) {
-    fchmod(fileno(f), S_IRUSR | S_IWUSR);
 /* FIXME: REMOVE AFTER 1.2.14 */
     bool old = 0;
 
@@ -1217,25 +1217,13 @@ write_tmp_userfile(char *fn, const struct userrec *bu, int idx)
     if (bot && bot->buildts < 1175102242) /* flood-* hacks */
       old = 1;
 
-    time_t tt = now;
-
-    lfprintf(f, "#4v: %s -- %s -- written %s", ver, conf.bot->nick, ctime(&tt));
-
-    if (!old)
-      ok += write_chans(f, idx);
-    else
-      ok += write_chans_compat(f, idx);
-    ok += write_vars_and_cmdpass(f, idx);
-    ok += write_bans(f, idx);
-    ok += write_exempts(f, idx);
-    ok += write_invites(f, idx);
-    if (ok != 5)
+    const char salt1[] = SALT1;
+    EncryptedStream stream(salt1);
+    stream_writeuserfile(stream, bu, idx, old);
+    if ((fwrite(stream.data(), 1, stream.length(), f) != stream.length()) || (fflush(f)))
       ok = 0;
-    for (struct userrec *u = (struct userrec *) bu; u && ok; u = u->next) {
-      if (!write_user(u, f, idx))
-        ok = 0;
-    }
     fclose(f);
+    fixmod(fn);
   }
   if (!ok)
     putlog(LOG_MISC, "*", "ERROR writing user file to transfer.");

+ 5 - 9
src/set.c

@@ -20,6 +20,7 @@
 #include "userrec.h"
 #include "userent.h"
 #include "rfc1459.h"
+#include "Stream.h"
 
 #include "set_default.h"
 
@@ -823,25 +824,20 @@ static char *var_rem_list(const char *botnick, variable_t *var, const char *elem
   return ret;
 }
 
-bool write_vars_and_cmdpass(FILE *f, int idx)
+void write_vars_and_cmdpass(Stream& stream, int idx)
 {
   putlog(LOG_DEBUG, "@", "Writing set entries...");
-  if (lfprintf(f, SET_NAME " - -\n") == EOF) /* Daemus */
-      return 0;
+  stream.printf(SET_NAME " - -\n");
 
   int i = 0;
 
   for (i = 0; vars[i].name; i++) {
     /* send blanks if our variable isn't set, theirs MIGHT be set and needs to be UNSET */
-    if (lfprintf(f, "@ %s %s\n", vars[i].name, vars[i].gdata ? vars[i].gdata : "") == EOF)
-      return 0;
+    stream.printf("@ %s %s\n", vars[i].name, vars[i].gdata ? vars[i].gdata : "");
   }
 
   for (struct cmd_pass *cp = cmdpass; cp; cp = cp->next)
-    if (lfprintf(f, "- %s %s\n", cp->name, cp->pass) == EOF)
-      return 0;
-
-  return 1;
+    stream.printf("- %s %s\n", cp->name, cp->pass);
 }
 
 

+ 1 - 1
src/set.h

@@ -76,7 +76,7 @@ extern int		cloak_script, fight_threshold, fork_interval, in_bots, set_noshare,
                         ison_time;
 extern rate_t		op_requests, close_threshold;
 
-bool write_vars_and_cmdpass (FILE *, int);
+void write_vars_and_cmdpass (Stream&, int);
 void var_userfile_share_line(char *, int, bool);
 void var_parse_my_botset();
 void init_vars();

+ 14 - 27
src/userent.c

@@ -37,6 +37,7 @@
 #include "dccutil.h"
 #include "crypt.h"
 #include "botmsg.h"
+#include "Stream.h"
 
 static struct user_entry_type *entry_type_list = NULL;
 
@@ -91,21 +92,16 @@ bool def_kill(struct user_entry *e)
   return 1;
 }
 
-bool write_userfile_protected(FILE * f, struct userrec *u, struct user_entry *e, int idx)
+void write_userfile_protected(Stream& stream, const struct userrec *u, const struct user_entry *e, int idx)
 {
   /* only write if saving local, or if sending to hub, or if sending to same user as entry */
-  if (idx == -1 || dcc[idx].hub || dcc[idx].user == u) {
-    if (lfprintf(f, "--%s %s\n", e->type->name, e->u.string) == EOF)
-      return 0;
-  }
-  return 1;
+  if (idx == -1 || dcc[idx].hub || dcc[idx].user == u)
+    stream.printf("--%s %s\n", e->type->name, e->u.string);
 }
 
-bool def_write_userfile(FILE * f, struct userrec *u, struct user_entry *e, int idx)
+void def_write_userfile(Stream& stream, const struct userrec *u, const struct user_entry *e, int idx)
 {
-  if (lfprintf(f, "--%s %s\n", e->type->name, e->u.string) == EOF)
-    return 0;
-  return 1;
+  stream.printf("--%s %s\n", e->type->name, e->u.string);
 }
 
 void *def_get(struct userrec *u, struct user_entry *e)
@@ -362,17 +358,15 @@ static bool set_gotshare(struct userrec *u, struct user_entry *e, char *buf, int
   return 1;
 }
 
-static bool set_write_userfile(FILE *f, struct userrec *u, struct user_entry *e, int idx)
+static void set_write_userfile(Stream& stream, const struct userrec *u, const struct user_entry *e, int idx)
 {
   /* only write if saving local, or if sending to hub, or if sending to same user as entry */
   if (idx == -1 || dcc[idx].hub || dcc[idx].user == u) {
     struct xtra_key *x = (struct xtra_key *) e->u.extra;
 
     for (; x; x = x->next)
-      if (lfprintf(f, "--%s %s %s\n", e->type->name, x->key, x->data ? x->data : "") == EOF)
-        return 0;
+      stream.printf("--%s %s %s\n", e->type->name, x->key, x->data ? x->data : "");
   }
-  return 1;
 }
 
 static bool set_kill(struct user_entry *e)
@@ -700,13 +694,11 @@ static bool laston_unpack(struct userrec *u, struct user_entry *e)
   return 1;
 }
 
-static bool laston_write_userfile(FILE * f, struct userrec *u, struct user_entry *e, int idx)
+static void laston_write_userfile(Stream& stream, const struct userrec *u, const struct user_entry *e, int idx)
 {
   struct laston_info *li = (struct laston_info *) e->u.extra;
 
-  if (lfprintf(f, "--LASTON %li %s\n", (long) li->laston, li->lastonplace ? li->lastonplace : "") == EOF)
-    return 0;
-  return 1;
+  stream.printf("--LASTON %li %s\n", (long) li->laston, li->lastonplace ? li->lastonplace : "");
 }
 
 static bool laston_kill(struct user_entry *e)
@@ -824,14 +816,11 @@ static bool botaddr_kill(struct user_entry *e)
   return 1;
 }
 
-static bool botaddr_write_userfile(FILE *f, struct userrec *u, struct user_entry *e, int idx)
+static void botaddr_write_userfile(Stream& stream, const struct userrec *u, const struct user_entry *e, int idx)
 {
   register struct bot_addr *bi = (struct bot_addr *) e->u.extra;
 
-  if (lfprintf(f,  "--%s %s:%u/%u:%u:%s\n", e->type->name, bi->address,
-  	      bi->telnet_port, bi->relay_port, bi->hublevel, bi->uplink) == EOF)
-    return 0;
-  return 1;
+  stream.printf("--%s %s:%u/%u:%u:%s\n", e->type->name, bi->address, bi->telnet_port, bi->relay_port, bi->hublevel, bi->uplink);
 }
 
 static bool botaddr_set(struct userrec *u, struct user_entry *e, void *buf)
@@ -914,14 +903,12 @@ struct user_entry_type USERENTRY_BOTADDR =
   "BOTADDR"
 };
 
-static bool hosts_write_userfile(FILE *f, struct userrec *u, struct user_entry *e, int idx)
+static void hosts_write_userfile(Stream& stream, const struct userrec *u, const struct user_entry *e, int idx)
 {
   struct list_type *h = NULL;
 
   for (h = (struct list_type *) e->u.extra; h; h = h->next)
-    if (lfprintf(f, "--HOSTS %s\n", h->extra) == EOF)
-      return 0;
-  return 1;
+    stream.printf("--HOSTS %s\n", h->extra);
 }
 
 static bool hosts_null(struct userrec *u, struct user_entry *e)

+ 25 - 26
src/userrec.c

@@ -49,6 +49,7 @@
 #include "core_binds.h"
 #include "socket.h"
 #include "net.h"
+#include "EncryptedStream.h"
 
 bool             noshare = 1;		/* don't send out to sharebots	    */
 struct userrec	*userlist = NULL;	/* user records are stored here	    */
@@ -354,14 +355,13 @@ int u_pass_match(struct userrec *u, char *in)
   return 0;
 }
 
-bool write_user(struct userrec *u, FILE * f, int idx)
+static void write_user(const struct userrec *u, Stream& stream, int idx)
 {
   char s[181] = "";
   struct flag_record fr = {FR_GLOBAL, u->flags, 0, 0 };
 
   build_flags(s, &fr, NULL);
-  if (lfprintf(f, "%s%-10s - %-24s\n", u->bot ? "-" : "", u->handle, s) == EOF)
-    return 0;
+  stream.printf("%s%-10s - %-24s\n", u->bot ? "-" : "", u->handle, s);
 
   struct chanset_t *cst = NULL;
 
@@ -375,8 +375,7 @@ bool write_user(struct userrec *u, FILE * f, int idx)
       fr.match = FR_CHAN;
       fr.chan = ch->flags;
       build_flags(s, &fr, NULL);
-      if (lfprintf(f, "! %-20s %li %-10s %s\n", ch->channel, (long) ch->laston, s, ch->info ? ch->info : "") == EOF)
-        return 0;
+      stream.printf("! %-20s %li %-10s %s\n", ch->channel, (long) ch->laston, s, ch->info ? ch->info : "");
     }
   }
   for (struct user_entry *ue = u->entries; ue; ue = ue->next) {
@@ -390,10 +389,9 @@ bool write_user(struct userrec *u, FILE * f, int idx)
     } else
 #endif
     if (ue->type)
-      if (conf.bot->hub && !ue->type->write_userfile(f, u, ue, idx))
-	return 0;
+      if (conf.bot->hub)
+        ue->type->write_userfile(stream, u, ue, idx);
   }
-  return 1;
 }
 
 static int sort_compare(struct userrec *a, struct userrec *b)
@@ -463,6 +461,19 @@ static void sort_userlist()
   }
 }
 
+void stream_writeuserfile(Stream& stream, const struct userrec *bu, int idx, old) {
+  time_t tt = now;
+  char s1[81] = "";
+
+  strcpy(s1, ctime(&tt));
+
+  stream.printf("#4v: %s -- %s -- written %s", ver, conf.bot->nick, s1);
+  channels_writeuserfile(stream, old);
+
+  for (const struct userrec *u = bu; u; u = u->next)
+    write_user(u, stream, -1);
+}
+
 /* Rewrite the entire user file. Call USERFILE hook as well, probably
  * causing the channel file to be rewritten as well.
  */
@@ -487,18 +498,13 @@ int write_userfile(int idx)
   fchmod(fileno(f), S_IRUSR | S_IWUSR);
 
   char backup[DIRMAX] = "";
-  bool ok = 1;
 
   if (idx >= 0)
     dprintf(idx, "Saving userfile...\n");
+
   if (sort_users)
     sort_userlist();
 
-  time_t tt = now;
-
-  lfprintf(f, "#4v: %s -- %s -- written %s", ver, conf.bot->nick, ctime(&tt));
-  fclose(f);
-
 
 /* FIXME: REMOVE AFTER 1.2.14 */
   bool old = 0;
@@ -506,19 +512,12 @@ int write_userfile(int idx)
   tand_t* bot = idx != -1 ? findbot(dcc[idx].nick) : NULL;
   if (bot && bot->buildts < 1175102242) /* flood-* hacks */
     old = 1;
-  channels_writeuserfile(old);
-
-  f = fopen(new_userfile, "a");
-  if (f == NULL) {
-    putlog(LOG_MISC, "*", "ERROR writing user file.");
-    free(new_userfile);
-    return 2;
-  }
-
   putlog(LOG_DEBUG, "@", "Writing user entries.");
-  for (struct userrec *u = userlist; u && ok; u = u->next)
-    ok = write_user(u, f, -1);
-  if (!ok || fflush(f)) {
+
+  const char salt1[] = SALT1;
+  EncryptedStream stream(salt1);
+  stream_writeuserfile(stream, userlist, idx, old);
+  if ((fwrite(stream.data(), 1, stream.length(), f) != stream.length()) || fflush(f)) {
     putlog(LOG_MISC, "*", "ERROR writing user file. (%s)", strerror(ferror(f)));
     fclose(f);
     free(new_userfile);

+ 1 - 1
src/userrec.h

@@ -11,7 +11,7 @@ int count_users(struct userrec *);
 int deluser(char *);
 int change_handle(struct userrec *, char *);
 void correct_handle(char *);
-bool write_user(struct userrec *u, FILE * f, int shr);
+void stream_writeuserfile(Stream&, const struct userrec *, int, bool = 0);
 int write_userfile(int);
 void touch_laston(struct userrec *, char *, time_t);
 void user_del_chan(char *);

+ 2 - 1
src/users.h

@@ -25,6 +25,7 @@ bool list_append(struct list_type **, struct list_type *);
 bool list_delete(struct list_type **, struct list_type *);
 bool list_contains(struct list_type *, struct list_type *);
 
+class Stream;
 
 /* New userfile format stuff
  */
@@ -34,7 +35,7 @@ struct user_entry_type {
   struct user_entry_type *next;
   bool (*got_share) (struct userrec *, struct user_entry *, char *, int);
   bool (*unpack) (struct userrec *, struct user_entry *);
-  bool (*write_userfile) (FILE *, struct userrec *, struct user_entry *, int);
+  void (*write_userfile) (Stream&, const struct userrec *, const struct user_entry *, int);
   bool (*kill) (struct user_entry *);
   void *(*get) (struct userrec *, struct user_entry *);
   bool (*set) (struct userrec *, struct user_entry *, void *);