+extern mode_t orig_umask;
+extern struct file_list *cur_flist, *first_flist, *dir_flist;
+extern struct chmod_mode_struct *daemon_chmod_modes;
+
+#if defined HAVE_ICONV_OPEN && defined HAVE_ICONV_H
+iconv_t ic_chck = (iconv_t)-1;
+
+static const char *default_charset(void)
+{
+#if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
+ return locale_charset();
+#elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
+ return nl_langinfo(CODESET);
+#else
+ return ""; /* Works with (at the very least) gnu iconv... */
+#endif
+}
+
+void setup_iconv()
+{
+ if (!am_server && !allow_8bit_chars) {
+ const char *defset = default_charset();
+
+ /* It's OK if this fails... */
+ ic_chck = iconv_open(defset, defset);
+
+ if (verbose > 3) {
+ if (ic_chck == (iconv_t)-1) {
+ rprintf(FINFO,
+ "note: iconv_open(\"%s\", \"%s\") failed (%d)"
+ " -- using isprint() instead of iconv().\n",
+ defset, defset, errno);
+ } else {
+ rprintf(FINFO,
+ "note: iconv_open(\"%s\", \"%s\") succeeded.\n",
+ defset, defset);
+ }
+ }
+ }
+}
+#endif
+
+/* This is used by sender.c with a valid f_out, and by receive.c with
+ * f_out = -1. */
+int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr,
+ uchar *type_ptr, char *buf, int *len_ptr)
+{
+ int len, iflags = 0;
+ struct file_list *flist;
+ uchar fnamecmp_type = FNAMECMP_FNAME;
+ int verbose_save, ndx;
+
+ read_loop:
+ while (1) {
+ ndx = read_ndx(f_in);
+
+ if (ndx >= 0)
+ break;
+ if (ndx == NDX_DONE)
+ return ndx;
+ if (!inc_recurse || am_sender)
+ goto invalid_ndx;
+ if (ndx == NDX_FLIST_EOF) {
+ flist_eof = 1;
+ send_msg(MSG_FLIST_EOF, "", 0);
+ continue;
+ }
+ ndx = NDX_FLIST_OFFSET - ndx;
+ if (ndx < 0 || ndx >= dir_flist->count) {
+ ndx = NDX_FLIST_OFFSET - ndx;
+ rprintf(FERROR,
+ "Invalid dir index: %d (%d - %d)\n",
+ ndx, NDX_FLIST_OFFSET,
+ NDX_FLIST_OFFSET - dir_flist->count);
+ exit_cleanup(RERR_PROTOCOL);
+ }
+ verbose_save = verbose;
+ verbose = 0; /* TODO allow verbose messages? */
+
+ /* Send everything read from f_in to msg_fd_out. */
+ send_msg_int(MSG_FLIST, ndx);
+ start_flist_forward(f_in);
+ flist = recv_file_list(f_in);
+ flist->parent_ndx = ndx;
+ stop_flist_forward();
+
+ verbose = verbose_save;
+ }
+
+ iflags = protocol_version >= 29 ? read_shortint(f_in)
+ : ITEM_TRANSFER | ITEM_MISSING_DATA;
+
+ /* Honor the old-style keep-alive indicator. */
+ if (protocol_version < 30
+ && ndx == cur_flist->count && iflags == ITEM_IS_NEW) {
+ if (am_sender)
+ maybe_send_keepalive();
+ goto read_loop;
+ }