summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am39
-rw-r--r--src/Makefile.in608
-rw-r--r--src/async-io-coroutine.h65
-rw-r--r--src/dropbox-client-util.c91
-rw-r--r--src/dropbox-client-util.h39
-rw-r--r--src/dropbox-client.c174
-rw-r--r--src/dropbox-client.h76
-rw-r--r--src/dropbox-command-client.c893
-rw-r--r--src/dropbox-command-client.h113
-rw-r--r--src/dropbox.c60
-rw-r--r--src/g-util.h49
-rw-r--r--src/nautilus-dropbox-hooks.c337
-rw-r--r--src/nautilus-dropbox-hooks.h79
-rw-r--r--src/nautilus-dropbox.c960
-rw-r--r--src/nautilus-dropbox.h69
15 files changed, 3652 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..54fb06a
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,39 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_builddir)
+
+nautilus_extensiondir=$(NAUTILUS_EXTENSION_DIR)
+
+nautilus_extension_LTLIBRARIES=libnautilus-dropbox.la
+
+libnautilus_dropbox_la_CFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -DEMBLEMDIR=\"$(EMBLEM_DIR)\" \
+ -Wall \
+ $(WARN_CFLAGS) \
+ $(DISABLE_DEPRECATED_CFLAGS) \
+ $(NAUTILUS_CFLAGS) \
+ $(GLIB_CFLAGS)
+
+if DEBUG
+libnautilus_dropbox_la_CFLAGS += -DND_DEBUG
+else
+libnautilus_dropbox_la_CFLAGS += -DG_DISABLE_ASSERT -DG_DISABLE_CHECKS
+endif
+
+libnautilus_dropbox_la_SOURCES = \
+ nautilus-dropbox.c \
+ nautilus-dropbox.h \
+ nautilus-dropbox-hooks.h \
+ nautilus-dropbox-hooks.c \
+ dropbox-command-client.h \
+ dropbox-command-client.c \
+ dropbox-client.c dropbox-client.h \
+ g-util.h \
+ async-io-coroutine.h \
+ dropbox-client-util.c \
+ dropbox-client-util.h \
+ dropbox.c
+
+libnautilus_dropbox_la_LDFLAGS = -module -avoid-version
+libnautilus_dropbox_la_LIBADD = $(NAUTILUS_LIBS) $(GLIB_LIBS)
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..548e911
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,608 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@DEBUG_TRUE@am__append_1 = -DND_DEBUG
+@DEBUG_FALSE@am__append_2 = -DG_DISABLE_ASSERT -DG_DISABLE_CHECKS
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(nautilus_extensiondir)"
+LTLIBRARIES = $(nautilus_extension_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libnautilus_dropbox_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libnautilus_dropbox_la_OBJECTS = \
+ libnautilus_dropbox_la-nautilus-dropbox.lo \
+ libnautilus_dropbox_la-nautilus-dropbox-hooks.lo \
+ libnautilus_dropbox_la-dropbox-command-client.lo \
+ libnautilus_dropbox_la-dropbox-client.lo \
+ libnautilus_dropbox_la-dropbox-client-util.lo \
+ libnautilus_dropbox_la-dropbox.lo
+libnautilus_dropbox_la_OBJECTS = $(am_libnautilus_dropbox_la_OBJECTS)
+libnautilus_dropbox_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) \
+ $(libnautilus_dropbox_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libnautilus_dropbox_la_SOURCES)
+DIST_SOURCES = $(libnautilus_dropbox_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EMBLEM_DIR = @EMBLEM_DIR@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_LIBS = @GLIB_LIBS@
+GREP = @GREP@
+HAVE_PKGCONFIG = @HAVE_PKGCONFIG@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NAUTILUS_CFLAGS = @NAUTILUS_CFLAGS@
+NAUTILUS_EXTENSION_DIR = @NAUTILUS_EXTENSION_DIR@
+NAUTILUS_LIBS = @NAUTILUS_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PYTHON = @PYTHON@
+RANLIB = @RANLIB@
+RST2MAN = @RST2MAN@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(top_builddir)
+
+nautilus_extensiondir = $(NAUTILUS_EXTENSION_DIR)
+nautilus_extension_LTLIBRARIES = libnautilus-dropbox.la
+libnautilus_dropbox_la_CFLAGS = -DDATADIR=\"$(datadir)\" \
+ -DEMBLEMDIR=\"$(EMBLEM_DIR)\" -Wall $(WARN_CFLAGS) \
+ $(DISABLE_DEPRECATED_CFLAGS) $(NAUTILUS_CFLAGS) $(GLIB_CFLAGS) \
+ $(am__append_1) $(am__append_2)
+libnautilus_dropbox_la_SOURCES = \
+ nautilus-dropbox.c \
+ nautilus-dropbox.h \
+ nautilus-dropbox-hooks.h \
+ nautilus-dropbox-hooks.c \
+ dropbox-command-client.h \
+ dropbox-command-client.c \
+ dropbox-client.c dropbox-client.h \
+ g-util.h \
+ async-io-coroutine.h \
+ dropbox-client-util.c \
+ dropbox-client-util.h \
+ dropbox.c
+
+libnautilus_dropbox_la_LDFLAGS = -module -avoid-version
+libnautilus_dropbox_la_LIBADD = $(NAUTILUS_LIBS) $(GLIB_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-nautilus_extensionLTLIBRARIES: $(nautilus_extension_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(nautilus_extensiondir)" || $(MKDIR_P) "$(DESTDIR)$(nautilus_extensiondir)"
+ @list='$(nautilus_extension_LTLIBRARIES)'; test -n "$(nautilus_extensiondir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(nautilus_extensiondir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(nautilus_extensiondir)"; \
+ }
+
+uninstall-nautilus_extensionLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nautilus_extension_LTLIBRARIES)'; test -n "$(nautilus_extensiondir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(nautilus_extensiondir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(nautilus_extensiondir)/$$f"; \
+ done
+
+clean-nautilus_extensionLTLIBRARIES:
+ -test -z "$(nautilus_extension_LTLIBRARIES)" || rm -f $(nautilus_extension_LTLIBRARIES)
+ @list='$(nautilus_extension_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libnautilus-dropbox.la: $(libnautilus_dropbox_la_OBJECTS) $(libnautilus_dropbox_la_DEPENDENCIES)
+ $(libnautilus_dropbox_la_LINK) -rpath $(nautilus_extensiondir) $(libnautilus_dropbox_la_OBJECTS) $(libnautilus_dropbox_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnautilus_dropbox_la-dropbox-client-util.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnautilus_dropbox_la-dropbox-client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnautilus_dropbox_la-dropbox-command-client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnautilus_dropbox_la-dropbox.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox-hooks.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libnautilus_dropbox_la-nautilus-dropbox.lo: nautilus-dropbox.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -MT libnautilus_dropbox_la-nautilus-dropbox.lo -MD -MP -MF $(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox.Tpo -c -o libnautilus_dropbox_la-nautilus-dropbox.lo `test -f 'nautilus-dropbox.c' || echo '$(srcdir)/'`nautilus-dropbox.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox.Tpo $(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nautilus-dropbox.c' object='libnautilus_dropbox_la-nautilus-dropbox.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -c -o libnautilus_dropbox_la-nautilus-dropbox.lo `test -f 'nautilus-dropbox.c' || echo '$(srcdir)/'`nautilus-dropbox.c
+
+libnautilus_dropbox_la-nautilus-dropbox-hooks.lo: nautilus-dropbox-hooks.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -MT libnautilus_dropbox_la-nautilus-dropbox-hooks.lo -MD -MP -MF $(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox-hooks.Tpo -c -o libnautilus_dropbox_la-nautilus-dropbox-hooks.lo `test -f 'nautilus-dropbox-hooks.c' || echo '$(srcdir)/'`nautilus-dropbox-hooks.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox-hooks.Tpo $(DEPDIR)/libnautilus_dropbox_la-nautilus-dropbox-hooks.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='nautilus-dropbox-hooks.c' object='libnautilus_dropbox_la-nautilus-dropbox-hooks.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -c -o libnautilus_dropbox_la-nautilus-dropbox-hooks.lo `test -f 'nautilus-dropbox-hooks.c' || echo '$(srcdir)/'`nautilus-dropbox-hooks.c
+
+libnautilus_dropbox_la-dropbox-command-client.lo: dropbox-command-client.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -MT libnautilus_dropbox_la-dropbox-command-client.lo -MD -MP -MF $(DEPDIR)/libnautilus_dropbox_la-dropbox-command-client.Tpo -c -o libnautilus_dropbox_la-dropbox-command-client.lo `test -f 'dropbox-command-client.c' || echo '$(srcdir)/'`dropbox-command-client.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libnautilus_dropbox_la-dropbox-command-client.Tpo $(DEPDIR)/libnautilus_dropbox_la-dropbox-command-client.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dropbox-command-client.c' object='libnautilus_dropbox_la-dropbox-command-client.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -c -o libnautilus_dropbox_la-dropbox-command-client.lo `test -f 'dropbox-command-client.c' || echo '$(srcdir)/'`dropbox-command-client.c
+
+libnautilus_dropbox_la-dropbox-client.lo: dropbox-client.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -MT libnautilus_dropbox_la-dropbox-client.lo -MD -MP -MF $(DEPDIR)/libnautilus_dropbox_la-dropbox-client.Tpo -c -o libnautilus_dropbox_la-dropbox-client.lo `test -f 'dropbox-client.c' || echo '$(srcdir)/'`dropbox-client.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libnautilus_dropbox_la-dropbox-client.Tpo $(DEPDIR)/libnautilus_dropbox_la-dropbox-client.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dropbox-client.c' object='libnautilus_dropbox_la-dropbox-client.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -c -o libnautilus_dropbox_la-dropbox-client.lo `test -f 'dropbox-client.c' || echo '$(srcdir)/'`dropbox-client.c
+
+libnautilus_dropbox_la-dropbox-client-util.lo: dropbox-client-util.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -MT libnautilus_dropbox_la-dropbox-client-util.lo -MD -MP -MF $(DEPDIR)/libnautilus_dropbox_la-dropbox-client-util.Tpo -c -o libnautilus_dropbox_la-dropbox-client-util.lo `test -f 'dropbox-client-util.c' || echo '$(srcdir)/'`dropbox-client-util.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libnautilus_dropbox_la-dropbox-client-util.Tpo $(DEPDIR)/libnautilus_dropbox_la-dropbox-client-util.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dropbox-client-util.c' object='libnautilus_dropbox_la-dropbox-client-util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -c -o libnautilus_dropbox_la-dropbox-client-util.lo `test -f 'dropbox-client-util.c' || echo '$(srcdir)/'`dropbox-client-util.c
+
+libnautilus_dropbox_la-dropbox.lo: dropbox.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -MT libnautilus_dropbox_la-dropbox.lo -MD -MP -MF $(DEPDIR)/libnautilus_dropbox_la-dropbox.Tpo -c -o libnautilus_dropbox_la-dropbox.lo `test -f 'dropbox.c' || echo '$(srcdir)/'`dropbox.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libnautilus_dropbox_la-dropbox.Tpo $(DEPDIR)/libnautilus_dropbox_la-dropbox.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dropbox.c' object='libnautilus_dropbox_la-dropbox.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libnautilus_dropbox_la_CFLAGS) $(CFLAGS) -c -o libnautilus_dropbox_la-dropbox.lo `test -f 'dropbox.c' || echo '$(srcdir)/'`dropbox.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(nautilus_extensiondir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool \
+ clean-nautilus_extensionLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nautilus_extensionLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-nautilus_extensionLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-nautilus_extensionLTLIBRARIES ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man \
+ install-nautilus_extensionLTLIBRARIES install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am \
+ uninstall-nautilus_extensionLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/async-io-coroutine.h b/src/async-io-coroutine.h
new file mode 100644
index 0000000..125d84e
--- /dev/null
+++ b/src/async-io-coroutine.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * async-io-coroutine.h
+ * Macros to simplify writing coroutines for the glib main loop.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef ASYNC_IO_COROUTINE_H
+#define ASYNC_IO_COROUTINE_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define CRBEGIN(pos) switch (pos) { case 0:
+#define CREND } return FALSE
+#define CRYIELD(pos) do { pos = __LINE__; return TRUE; case __LINE__:;} while (0)
+#define CRHALT return FALSE
+
+#define CRREADLINE(pos, chan, where) \
+ while (1) { \
+ gchar *__line; \
+ gsize __line_length, __newline_pos; \
+ GIOStatus __iostat; \
+ \
+ __iostat = g_io_channel_read_line(chan, &__line, \
+ &__line_length, \
+ &__newline_pos, NULL); \
+ if (__iostat == G_IO_STATUS_AGAIN) { \
+ CRYIELD(pos); \
+ } \
+ else if (__iostat == G_IO_STATUS_NORMAL) { \
+ *(__line + __newline_pos) = '\0'; \
+ where = __line; \
+ break; \
+ } \
+ else if (__iostat == G_IO_STATUS_EOF || \
+ __iostat == G_IO_STATUS_ERROR) { \
+ CRHALT; \
+ } \
+ else { \
+ g_assert_not_reached(); \
+ CRHALT; \
+ } \
+ }
+
+G_END_DECLS
+
+#endif
diff --git a/src/dropbox-client-util.c b/src/dropbox-client-util.c
new file mode 100644
index 0000000..2351c81
--- /dev/null
+++ b/src/dropbox-client-util.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * dropbox-client-util.c
+ * Utility functions for implementing dropbox clients.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+
+static gchar chars_not_to_escape[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 34, 127,
+ -128, -127, -126, -125, -124, -123, -122, -121, -120, -119,
+ -118, -117, -116, -115, -114, -113, -112, -111, -110, -109,
+ -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,
+ -98, -97, -96, -95, -94, -93, -92, -91, -90, -89,
+ -88, -87, -86, -85, -84, -83, -82, -81, -80, -79,
+ -78, -77, -76, -75, -74, -73, -72, -71, -70, -69,
+ -68, -67, -66, -65, -64, -63, -62, -61, -60, -59,
+ -58, -57, -56, -55, -54, -53, -52, -51, -50, -49,
+ -48, -47, -46, -45, -44, -43, -42, -41, -40, -39,
+ -38, -37, -36, -35, -34, -33, -32, -31, -30, -29,
+ -28, -27, -26, -25, -24, -23, -22, -21, -20, -19,
+ -18, -17, -16, -15, -14, -13, -12, -11, -10, -9,
+ -8, -7, -6, -5, -4, -3, -2, -1, 0
+};
+
+gchar *dropbox_client_util_sanitize(const gchar *a) {
+ /* this function escapes teh following utf-8 characters:
+ * '\\', '\n', '\t'
+ */
+ return g_strescape(a, chars_not_to_escape);
+}
+
+gchar *dropbox_client_util_desanitize(const gchar *a) {
+ return g_strcompress(a);
+}
+
+gboolean
+dropbox_client_util_command_parse_arg(const gchar *line, GHashTable *return_table) {
+ gchar **argval;
+ guint len;
+ gboolean retval;
+
+ argval = g_strsplit(line, "\t", 0);
+ len = g_strv_length(argval);
+
+ /* debug("parsed: (%d) %s", len, line); */
+
+ if (len > 1) {
+ int i;
+ gchar **vals;
+
+ vals = g_new(gchar *, len);
+ vals[len - 1] = NULL;
+
+ for (i = 1; argval[i] != NULL; i++) {
+ vals[i-1] = dropbox_client_util_desanitize(argval[i]);
+
+ }
+
+ g_hash_table_insert(return_table,
+ dropbox_client_util_desanitize(argval[0]),
+ vals);
+ retval = TRUE;
+ }
+ else {
+ retval = FALSE;
+ }
+
+ g_strfreev(argval);
+ return retval;
+}
+
diff --git a/src/dropbox-client-util.h b/src/dropbox-client-util.h
new file mode 100644
index 0000000..7813a3f
--- /dev/null
+++ b/src/dropbox-client-util.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * dropbox-client-util.h
+ * Header file for dropbox-client-util.c
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DROPBOX_CLIENT_UTIL_H
+#define DROPBOX_CLIENT_UTIL_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gchar *dropbox_client_util_sanitize(const gchar *a);
+gchar *dropbox_client_util_desanitize(const gchar *a);
+
+gboolean
+dropbox_client_util_command_parse_arg(const gchar *line, GHashTable *return_table);
+
+G_END_DECLS
+
+#endif
diff --git a/src/dropbox-client.c b/src/dropbox-client.c
new file mode 100644
index 0000000..dbd4f77
--- /dev/null
+++ b/src/dropbox-client.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * dropbox-client.c
+ * Implements connection handling and C interface for interfacing with the Dropbox daemon.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <glib.h>
+
+#include "g-util.h"
+#include "dropbox-command-client.h"
+#include "nautilus-dropbox-hooks.h"
+#include "dropbox-client.h"
+
+static void
+hook_on_connect(DropboxClient *dc) {
+ dc->hook_connect_called = TRUE;
+
+ if (dc->command_connect_called) {
+ debug("client connection");
+ g_hook_list_invoke(&(dc->onconnect_hooklist), FALSE);
+ /* reset flags */
+ dc->hook_connect_called = dc->command_connect_called = FALSE;
+ }
+}
+
+static void
+command_on_connect(DropboxClient *dc) {
+ dc->command_connect_called = TRUE;
+
+ if (dc->hook_connect_called) {
+ debug("client connection");
+ g_hook_list_invoke(&(dc->onconnect_hooklist), FALSE);
+ /* reset flags */
+ dc->hook_connect_called = dc->command_connect_called = FALSE;
+ }
+}
+
+static void
+command_on_disconnect(DropboxClient *dc) {
+ dc->command_disconnect_called = TRUE;
+
+ if (dc->hook_disconnect_called) {
+ debug("client disconnect");
+ g_hook_list_invoke(&(dc->ondisconnect_hooklist), FALSE);
+ /* reset flags */
+ dc->hook_disconnect_called = dc->command_disconnect_called = FALSE;
+ }
+ else {
+ nautilus_dropbox_hooks_force_reconnect(&(dc->hookserv));
+ }
+}
+
+static void
+hook_on_disconnect(DropboxClient *dc) {
+ dc->hook_disconnect_called = TRUE;
+
+ if (dc->command_disconnect_called) {
+ debug("client disconnect");
+ g_hook_list_invoke(&(dc->ondisconnect_hooklist), FALSE);
+ /* reset flags */
+ dc->hook_disconnect_called = dc->command_disconnect_called = FALSE;
+ }
+ else {
+ dropbox_command_client_force_reconnect(&(dc->dcc));
+ }
+}
+
+gboolean
+dropbox_client_is_connected(DropboxClient *dc) {
+ return (dropbox_command_client_is_connected(&(dc->dcc)) &&
+ nautilus_dropbox_hooks_is_connected(&(dc->hookserv)));
+}
+
+void
+dropbox_client_force_reconnect(DropboxClient *dc) {
+ if (dropbox_client_is_connected(dc) == TRUE) {
+ debug("forcing client to reconnect");
+ dropbox_command_client_force_reconnect(&(dc->dcc));
+ nautilus_dropbox_hooks_force_reconnect(&(dc->hookserv));
+ }
+}
+
+/* should only be called once on initialization */
+void
+dropbox_client_setup(DropboxClient *dc) {
+ nautilus_dropbox_hooks_setup(&(dc->hookserv));
+ dropbox_command_client_setup(&(dc->dcc));
+
+ g_hook_list_init(&(dc->ondisconnect_hooklist), sizeof(GHook));
+ g_hook_list_init(&(dc->onconnect_hooklist), sizeof(GHook));
+
+ dc->hook_disconnect_called = dc->command_disconnect_called = FALSE;
+ dc->hook_connect_called = dc->command_connect_called = FALSE;
+
+ nautilus_dropbox_hooks_add_on_connect_hook(&(dc->hookserv),
+ (DropboxHookClientConnectHook)
+ hook_on_connect, dc);
+
+ dropbox_command_client_add_on_connect_hook(&(dc->dcc),
+ (DropboxCommandClientConnectHook)
+ command_on_connect, dc);
+
+ nautilus_dropbox_hooks_add_on_disconnect_hook(&(dc->hookserv),
+ (DropboxHookClientConnectHook)
+ hook_on_disconnect, dc);
+
+ dropbox_command_client_add_on_disconnect_hook(&(dc->dcc),
+ (DropboxCommandClientConnectHook)
+ command_on_disconnect, dc);
+}
+
+/* not thread safe */
+void
+dropbox_client_add_on_disconnect_hook(DropboxClient *dc,
+ DropboxClientConnectHook dhcch,
+ gpointer ud) {
+ GHook *newhook;
+
+ newhook = g_hook_alloc(&(dc->ondisconnect_hooklist));
+ newhook->func = dhcch;
+ newhook->data = ud;
+
+ g_hook_append(&(dc->ondisconnect_hooklist), newhook);
+}
+
+/* not thread safe */
+void
+dropbox_client_add_on_connect_hook(DropboxClient *dc,
+ DropboxClientConnectHook dhcch,
+ gpointer ud) {
+ GHook *newhook;
+
+ newhook = g_hook_alloc(&(dc->onconnect_hooklist));
+ newhook->func = dhcch;
+ newhook->data = ud;
+
+ g_hook_append(&(dc->onconnect_hooklist), newhook);
+}
+
+/* not thread safe */
+void
+dropbox_client_add_connection_attempt_hook(DropboxClient *dc,
+ DropboxClientConnectionAttemptHook dhcch,
+ gpointer ud) {
+ debug("shouldn't be here...");
+
+ dropbox_command_client_add_connection_attempt_hook(&(dc->dcc),
+ dhcch, ud);
+}
+
+/* should only be called once on initialization */
+void
+dropbox_client_start(DropboxClient *dc) {
+ debug("starting connections");
+ nautilus_dropbox_hooks_start(&(dc->hookserv));
+ dropbox_command_client_start(&(dc->dcc));
+}
diff --git a/src/dropbox-client.h b/src/dropbox-client.h
new file mode 100644
index 0000000..c981c44
--- /dev/null
+++ b/src/dropbox-client.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * dropbox-client.h
+ * Header file for dropbox-client.c
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DROPBOX_CLIENT_H
+#define DROPBOX_CLIENT_H
+
+#include <glib.h>
+#include "dropbox-command-client.h"
+#include "nautilus-dropbox-hooks.h"
+
+G_BEGIN_DECLS
+
+typedef struct {
+ DropboxCommandClient dcc;
+ NautilusDropboxHookserv hookserv;
+ GHookList onconnect_hooklist;
+ GHookList ondisconnect_hooklist;
+ gboolean hook_connect_called;
+ gboolean command_connect_called;
+ gboolean hook_disconnect_called;
+ gboolean command_disconnect_called;
+} DropboxClient;
+
+typedef void (*DropboxClientConnectionAttemptHook)(guint, gpointer);
+typedef GHookFunc DropboxClientConnectHook;
+
+void
+dropbox_client_setup(DropboxClient *dc);
+
+void
+dropbox_client_start(DropboxClient *dc);
+
+gboolean
+dropbox_client_is_connected(DropboxClient *dc);
+
+void
+dropbox_client_force_reconnect(DropboxClient *dc);
+
+void
+dropbox_client_add_on_connect_hook(DropboxClient *dc,
+ DropboxClientConnectHook dhcch,
+ gpointer ud);
+
+void
+dropbox_client_add_on_disconnect_hook(DropboxClient *dc,
+ DropboxClientConnectHook dhcch,
+ gpointer ud);
+
+void
+dropbox_client_add_connection_attempt_hook(DropboxClient *dc,
+ DropboxClientConnectionAttemptHook dhcch,
+ gpointer ud);
+
+G_END_DECLS
+
+#endif
diff --git a/src/dropbox-command-client.c b/src/dropbox-command-client.c
new file mode 100644
index 0000000..bdec125
--- /dev/null
+++ b/src/dropbox-command-client.c
@@ -0,0 +1,893 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * dropbox-command-client.c
+ * Implements connection handling and C interface for the Dropbox command socket.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "g-util.h"
+#include "dropbox-client-util.h"
+#include "dropbox-command-client.h"
+#include "nautilus-dropbox.h"
+#include "nautilus-dropbox-hooks.h"
+
+/* TODO: make this asynchronous ;) */
+
+/*
+ this is a tiny hack, necessitated by the fact that
+ finish_file info command is in nautilus_dropbox,
+ this can be cleaned up once the file_info_command isn't a special
+ case anylonger
+*/
+gboolean nautilus_dropbox_finish_file_info_command(DropboxFileInfoCommandResponse *);
+
+typedef struct {
+ DropboxCommandClient *dcc;
+ guint connect_attempt;
+} ConnectionAttempt;
+
+typedef struct {
+ DropboxCommandClientConnectionAttemptHook h;
+ gpointer ud;
+} DropboxCommandClientConnectionAttempt;
+
+typedef struct {
+ DropboxGeneralCommand *dgc;
+ GHashTable *response;
+} DropboxGeneralCommandResponse;
+
+static gboolean
+on_connect(DropboxCommandClient *dcc) {
+ g_hook_list_invoke(&(dcc->onconnect_hooklist), FALSE);
+ return FALSE;
+}
+
+static gboolean
+on_disconnect(DropboxCommandClient *dcc) {
+ g_hook_list_invoke(&(dcc->ondisconnect_hooklist), FALSE);
+ return FALSE;
+}
+
+static gboolean
+on_connection_attempt(ConnectionAttempt *ca) {
+ GList *ll;
+
+ for (ll = ca->dcc->ca_hooklist; ll != NULL; ll = g_list_next(ll)) {
+ DropboxCommandClientConnectionAttempt *dccca =
+ (DropboxCommandClientConnectionAttempt *)(ll->data);
+ dccca->h(ca->connect_attempt, dccca->ud);
+ }
+
+ g_free(ca);
+
+ return FALSE;
+}
+
+static gboolean
+receive_args_until_done(GIOChannel *chan, GHashTable *return_table,
+ GError **err) {
+ GIOStatus iostat;
+ GError *tmp_error = NULL;
+ guint numargs = 0;
+
+ while (1) {
+ gchar *line;
+ gsize term_pos;
+
+ /* if we are getting too many args, connection could be malicious */
+ if (numargs >= 20) {
+ g_set_error(err,
+ g_quark_from_static_string("malicious connection"),
+ 0, "malicious connection");
+ return FALSE;
+ }
+
+ /* get the string */
+ iostat = g_io_channel_read_line(chan, &line, NULL,
+ &term_pos, &tmp_error);
+ if (iostat == G_IO_STATUS_ERROR || tmp_error != NULL) {
+ g_free(line);
+ if (tmp_error != NULL) {
+ g_propagate_error(err, tmp_error);
+ }
+ return FALSE;
+ }
+ else if (iostat == G_IO_STATUS_EOF) {
+ g_free(line);
+ g_set_error(err,
+ g_quark_from_static_string("connection closed"),
+ 0, "connection closed");
+ return FALSE;
+ }
+
+ *(line+term_pos) = '\0';
+
+ if (strcmp("done", line) == 0) {
+ g_free(line);
+ break;
+ }
+ else {
+ gboolean parse_result;
+
+ parse_result = dropbox_client_util_command_parse_arg(line, return_table);
+ g_free(line);
+
+ if (FALSE == parse_result) {
+ g_set_error(err,
+ g_quark_from_static_string("parse error"),
+ 0, "parse error");
+ return FALSE;
+ }
+ }
+
+ numargs += 1;
+ }
+
+ return TRUE;
+}
+
+static void my_g_hash_table_get_keys_helper(gpointer key,
+ gpointer value,
+ GList **ud) {
+ *ud = g_list_append(*ud, key);
+}
+
+static GList *my_g_hash_table_get_keys(GHashTable *ght) {
+ GList *list = NULL;
+ g_hash_table_foreach(ght, (GHFunc)
+ my_g_hash_table_get_keys_helper, &list);
+ return list;
+}
+
+/*
+ sends a command to the dropbox server
+ returns an hash of the return values
+
+ in theory, this should disconnection errors
+ but it doesn't matter right now, any error is a sufficient
+ condition to disconnect
+*/
+static GHashTable *
+send_command_to_db(GIOChannel *chan, const gchar *command_name,
+ GHashTable *args, GError **err) {
+ GError *tmp_error = NULL;
+ GIOStatus iostat;
+ gsize bytes_trans;
+ gchar *line;
+
+ g_assert(chan != NULL);
+ g_assert(command_name != NULL);
+
+
+#define WRITE_OR_DIE_SANI(s,l) { \
+ gchar *sani_s; \
+ sani_s = dropbox_client_util_sanitize(s); \
+ iostat = g_io_channel_write_chars(chan, sani_s,l, &bytes_trans, \
+ &tmp_error); \
+ g_free(sani_s); \
+ if (iostat == G_IO_STATUS_ERROR || \
+ iostat == G_IO_STATUS_AGAIN) { \
+ if (tmp_error != NULL) { \
+ g_propagate_error(err, tmp_error); \
+ } \
+ return NULL; \
+ } \
+ }
+
+#define WRITE_OR_DIE(s,l) { \
+ iostat = g_io_channel_write_chars(chan, s,l, &bytes_trans, \
+ &tmp_error); \
+ if (iostat == G_IO_STATUS_ERROR || \
+ iostat == G_IO_STATUS_AGAIN) { \
+ if (tmp_error != NULL) { \
+ g_propagate_error(err, tmp_error); \
+ } \
+ return NULL; \
+ } \
+ }
+
+ /* send command to server */
+ WRITE_OR_DIE_SANI(command_name, -1);
+ WRITE_OR_DIE("\n", -1);
+
+ if (args != NULL) {
+ GList *keys, *li;
+
+ /* oh god */
+ keys = glib_check_version(2, 14, 0)
+ ? my_g_hash_table_get_keys(args)
+ : g_hash_table_get_keys(args);
+
+ for (li = keys; li != NULL; li = g_list_next(li)) {
+ int i;
+ gchar **value;
+
+ WRITE_OR_DIE_SANI((gchar *) li->data, -1);
+
+ value = g_hash_table_lookup(args, li->data);
+ for (i = 0; value[i] != NULL; i++) {
+ WRITE_OR_DIE("\t", -1);
+ WRITE_OR_DIE_SANI(value[i], -1);
+ }
+ WRITE_OR_DIE("\n", -1);
+ }
+
+ g_list_free(keys);
+ }
+
+ WRITE_OR_DIE("done\n", -1);
+
+#undef WRITE_OR_DIE
+#undef WRITE_OR_DIE_SANI
+
+ g_io_channel_flush(chan, &tmp_error);
+ if (tmp_error != NULL) {
+ g_propagate_error(err, tmp_error);
+ return NULL;
+ }
+
+ /* now we have to read the data */
+ iostat = g_io_channel_read_line(chan, &line, NULL,
+ NULL, &tmp_error);
+ if (iostat == G_IO_STATUS_ERROR) {
+ g_assert(line == NULL);
+ g_propagate_error(err, tmp_error);
+ return NULL;
+ }
+ else if (iostat == G_IO_STATUS_AGAIN) {
+ g_assert(line == NULL);
+ g_set_error(err,
+ g_quark_from_static_string("dropbox command connection timed out"),
+ 0,
+ "dropbox command connection timed out");
+ return NULL;
+ }
+ else if (iostat == G_IO_STATUS_EOF) {
+ g_assert(line == NULL);
+ g_set_error(err,
+ g_quark_from_static_string("dropbox command connection closed"),
+ 0,
+ "dropbox command connection closed");
+ return NULL;
+ }
+
+ /* if the response was okay */
+ if (strncmp(line, "ok\n", 3) == 0) {
+ GHashTable *return_table =
+ g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_strfreev);
+
+ g_free(line);
+ line = NULL;
+
+ receive_args_until_done(chan, return_table, &tmp_error);
+ if (tmp_error != NULL) {
+ g_hash_table_destroy(return_table);
+ g_propagate_error(err, tmp_error);
+ return NULL;
+ }
+
+ return return_table;
+ }
+ /* otherwise */
+ else {
+ /* read errors off until we get done */
+ do {
+ g_free(line);
+ line = NULL;
+
+ /* clear string */
+ iostat = g_io_channel_read_line(chan, &line, NULL,
+ NULL, &tmp_error);
+ if (iostat == G_IO_STATUS_ERROR) {
+ g_assert(line == NULL);
+ g_propagate_error(err, tmp_error);
+ return NULL;
+ }
+ else if (iostat == G_IO_STATUS_AGAIN) {
+ g_assert(line == NULL);
+ g_set_error(err,
+ g_quark_from_static_string("dropbox command connection timed out"),
+ 0,
+ "dropbox command connection timed out");
+ return NULL;
+
+ }
+ else if (iostat == G_IO_STATUS_EOF) {
+ g_assert(line == NULL);
+ g_set_error(err,
+ g_quark_from_static_string("dropbox command connection closed"),
+ 0,
+ "dropbox command connection closed");
+ return NULL;
+ }
+
+ /* we got our line */
+ } while (strncmp(line, "done\n", 5) != 0);
+
+ g_free(line);
+ return NULL;
+ }
+}
+
+static void
+do_file_info_command(GIOChannel *chan, DropboxFileInfoCommand *dfic, GError **gerr) {
+ /* we need to send two requests to dropbox:
+ file status, and folder_tags */
+ GError *tmp_gerr = NULL;
+ DropboxFileInfoCommandResponse *dficr;
+ GHashTable *file_status_response = NULL, *args, *folder_tag_response = NULL, *emblems_response = NULL;
+ gchar *filename = NULL;
+
+ {
+ gchar *filename_un, *uri;
+ uri = nautilus_file_info_get_uri(dfic->file);
+ filename_un = uri ? g_filename_from_uri(uri, NULL, NULL): NULL;
+ g_free(uri);
+ if (filename_un) {
+ filename = g_filename_to_utf8(filename_un, -1, NULL, NULL, NULL);
+ g_free(filename_un);
+ if (filename == NULL) {
+ /* oooh, filename wasn't correctly encoded. mark as */
+ debug("file wasn't correctly encoded %s", filename_un);
+ }
+ }
+ }
+
+ if (filename == NULL) {
+ /* We couldn't get the filename. Just return empty. */
+ goto exit;
+ }
+
+ args = g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_strfreev);
+ {
+ gchar **path_arg;
+ path_arg = g_new(gchar *, 2);
+ path_arg[0] = g_strdup(filename);
+ path_arg[1] = NULL;
+ g_hash_table_insert(args, g_strdup("path"), path_arg);
+ }
+
+ emblems_response = send_command_to_db(chan, "get_emblems", args, NULL);
+ if (emblems_response) {
+ /* Don't need to do the other calls. */
+ g_hash_table_unref(args);
+ goto exit;
+ }
+
+ /* send status command to server */
+ file_status_response = send_command_to_db(chan, "icon_overlay_file_status",
+ args, &tmp_gerr);
+ g_hash_table_unref(args);
+ args = NULL;
+ if (tmp_gerr != NULL) {
+ g_free(filename);
+ g_assert(file_status_response == NULL);
+ g_propagate_error(gerr, tmp_gerr);
+ return;
+ }
+
+ if (nautilus_file_info_is_directory(dfic->file)) {
+ args = g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_strfreev);
+ {
+ gchar **paths_arg;
+ paths_arg = g_new(gchar *, 2);
+ paths_arg[0] = g_strdup(filename);
+ paths_arg[1] = NULL;
+ g_hash_table_insert(args, g_strdup("path"), paths_arg);
+ }
+
+ folder_tag_response =
+ send_command_to_db(chan, "get_folder_tag", args, &tmp_gerr);
+ g_hash_table_unref(args);
+ args = NULL;
+ if (tmp_gerr != NULL) {
+ if (file_status_response != NULL)
+ g_hash_table_destroy(file_status_response);
+ g_assert(folder_tag_response == NULL);
+ g_propagate_error(gerr, tmp_gerr);
+ return;
+ }
+ }
+
+ /* great server responded perfectly,
+ now let's get this request done,
+ ...in the glib main loop */
+exit:
+ dficr = g_new0(DropboxFileInfoCommandResponse, 1);
+ dficr->dfic = dfic;
+ dficr->folder_tag_response = folder_tag_response;
+ dficr->file_status_response = file_status_response;
+ dficr->emblems_response = emblems_response;
+ g_idle_add((GSourceFunc) nautilus_dropbox_finish_file_info_command, dficr);
+
+ g_free(filename);
+
+ return;
+}
+
+static gboolean
+finish_general_command(DropboxGeneralCommandResponse *dgcr) {
+ if (dgcr->dgc->handler != NULL) {
+ dgcr->dgc->handler(dgcr->response, dgcr->dgc->handler_ud);
+ }
+
+ if (dgcr->response != NULL) {
+ g_hash_table_unref(dgcr->response);
+ }
+
+ g_free(dgcr->dgc->command_name);
+ if (dgcr->dgc->command_args != NULL) {
+ g_hash_table_unref(dgcr->dgc->command_args);
+ }
+ g_free(dgcr->dgc);
+ g_free(dgcr);
+
+ return FALSE;
+}
+
+static void
+do_general_command(GIOChannel *chan, DropboxGeneralCommand *dcac,
+ GError **gerr) {
+ GError *tmp_gerr = NULL;
+ GHashTable *response;
+
+ /* send status command to server */
+ response = send_command_to_db(chan, dcac->command_name,
+ dcac->command_args, &tmp_gerr);
+ if (tmp_gerr != NULL) {
+ g_assert(response == NULL);
+ g_propagate_error(gerr, tmp_gerr);
+ return;
+ }
+
+ /* great, the server did the command perfectly,
+ now call the handler with the response */
+ {
+ DropboxGeneralCommandResponse *dgcr = g_new0(DropboxGeneralCommandResponse, 1);
+ dgcr->dgc = dcac;
+ dgcr->response = response;
+ finish_general_command(dgcr);
+ }
+
+ return;
+}
+
+static gboolean
+check_connection(GIOChannel *chan) {
+ gchar fake_buf[4096];
+ gsize bytes_read;
+ GError *tmp_error = NULL;
+ GIOFlags flags;
+ GIOStatus ret, iostat;
+
+ flags = g_io_channel_get_flags(chan);
+
+ /* set non-blocking */
+ ret = g_io_channel_set_flags(chan, flags | G_IO_FLAG_NONBLOCK, NULL);
+ if (ret == G_IO_STATUS_ERROR) {
+ return FALSE;
+ }
+
+ iostat = g_io_channel_read_chars(chan, fake_buf,
+ sizeof(fake_buf),
+ &bytes_read, &tmp_error);
+
+ ret = g_io_channel_set_flags(chan, flags, NULL);
+ if (ret == G_IO_STATUS_ERROR) {
+ return FALSE;
+ }
+
+ /* this makes us disconnect from bad servers
+ (those that send us information without us asking for it) */
+ return iostat == G_IO_STATUS_AGAIN;
+}
+
+static gpointer
+dropbox_command_client_thread(DropboxCommandClient *data);
+
+static void
+end_request(DropboxCommand *dc) {
+ if ((gpointer (*)(DropboxCommandClient *data)) dc != &dropbox_command_client_thread) {
+ switch (dc->request_type) {
+ case GET_FILE_INFO: {
+ DropboxFileInfoCommand *dfic = (DropboxFileInfoCommand *) dc;
+ DropboxFileInfoCommandResponse *dficr = g_new0(DropboxFileInfoCommandResponse, 1);
+ dficr->dfic = dfic;
+ dficr->file_status_response = NULL;
+ dficr->emblems_response = NULL;
+ g_idle_add((GSourceFunc) nautilus_dropbox_finish_file_info_command, dficr);
+ }
+ break;
+ case GENERAL_COMMAND: {
+ DropboxGeneralCommand *dgc = (DropboxGeneralCommand *) dc;
+ DropboxGeneralCommandResponse *dgcr = g_new0(DropboxGeneralCommandResponse, 1);
+ dgcr->dgc = dgc;
+ dgcr->response = NULL;
+ finish_general_command(dgcr);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ }
+}
+
+
+static gpointer
+dropbox_command_client_thread(DropboxCommandClient *dcc) {
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+ int connection_attempts = 1;
+
+ /* intialize address structure */
+ addr.sun_family = AF_UNIX;
+ g_snprintf(addr.sun_path,
+ sizeof(addr.sun_path),
+ "%s/.dropbox/command_socket",
+ g_get_home_dir());
+ addr_len = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path);
+
+ while (1) {
+ GIOChannel *chan = NULL;
+ GError *gerr = NULL;
+ int sock;
+ gboolean failflag = TRUE;
+
+ do {
+ int flags;
+
+ if (0 > (sock = socket(PF_UNIX, SOCK_STREAM, 0))) {
+ /* WTF */
+ break;
+ }
+
+ /* set timeout on socket, to protect against
+ bad servers */
+ {
+ struct timeval tv = {3, 0};
+ if (0 > setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
+ &tv, sizeof(struct timeval)) ||
+ 0 > setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
+ &tv, sizeof(struct timeval))) {
+ /* debug("setsockopt failed"); */
+ break;
+ }
+ }
+
+ /* set native non-blocking, for connect timeout */
+ {
+ if ((flags = fcntl(sock, F_GETFL, 0)) < 0 ||
+ fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0) {
+ /* debug("fcntl failed"); */
+ break;
+ }
+ }
+
+ /* if there was an error we have to try again later */
+ if (connect(sock, (struct sockaddr *) &addr, addr_len) < 0) {
+ if (errno == EINPROGRESS) {
+ fd_set writers;
+ struct timeval tv = {1, 0};
+
+ FD_ZERO(&writers);
+ FD_SET(sock, &writers);
+
+ /* if nothing was ready after 3 seconds, fail out homie */
+ if (select(sock+1, NULL, &writers, NULL, &tv) == 0) {
+ /* debug("connection timeout"); */
+ break;
+ }
+
+ if (connect(sock, (struct sockaddr *) &addr, addr_len) < 0) {
+ /* debug("couldn't connect to command server after 1 second"); */
+ break;
+ }
+ }
+ /* errno != EINPROGRESS */
+ else {
+ /* debug("bad connection"); */
+ break;
+ }
+ }
+
+ /* set back to blocking */
+ if (fcntl(sock, F_SETFL, flags) < 0) {
+ /* debug("fcntl2 failed"); */
+ break;
+ }
+
+ failflag = FALSE;
+ } while (0);
+
+ if (failflag) {
+ ConnectionAttempt *ca = g_new(ConnectionAttempt, 1);
+ ca->dcc = dcc;
+ ca->connect_attempt = connection_attempts;
+ g_idle_add((GSourceFunc) on_connection_attempt, ca);
+ if (sock >= 0) {
+ close(sock);
+ }
+ g_usleep(G_USEC_PER_SEC);
+ connection_attempts++;
+ continue;
+ }
+ else {
+ connection_attempts = 0;
+ }
+
+ /* connected */
+ debug("command client connected");
+
+ chan = g_io_channel_unix_new(sock);
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ g_io_channel_set_line_term(chan, "\n", -1);
+
+#define SET_CONNECTED_STATE(s) { \
+ g_mutex_lock(dcc->command_connected_mutex); \
+ dcc->command_connected = s; \
+ g_mutex_unlock(dcc->command_connected_mutex); \
+ }
+
+ SET_CONNECTED_STATE(TRUE);
+
+ g_idle_add((GSourceFunc) on_connect, dcc);
+
+ while (1) {
+ DropboxCommand *dc;
+
+ while (1) {
+ GTimeVal gtv;
+
+ g_get_current_time(&gtv);
+ g_time_val_add(&gtv, G_USEC_PER_SEC / 10);
+ /* get a request from nautilus */
+ dc = g_async_queue_timed_pop(dcc->command_queue, &gtv);
+ if (dc != NULL) {
+ break;
+ }
+ else {
+ if (check_connection(chan) == FALSE) {
+ goto BADCONNECTION;
+ }
+ }
+ }
+
+ /* this pointer should be unique */
+ if ((gpointer (*)(DropboxCommandClient *data)) dc == &dropbox_command_client_thread) {
+ debug("got a reset request");
+ goto BADCONNECTION;
+ }
+
+ switch (dc->request_type) {
+ case GET_FILE_INFO: {
+ debug("doing file info command");
+ do_file_info_command(chan, (DropboxFileInfoCommand *) dc, &gerr);
+ }
+ break;
+ case GENERAL_COMMAND: {
+ debug("doing general command");
+ do_general_command(chan, (DropboxGeneralCommand *) dc, &gerr);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ debug("done.");
+
+ if (gerr != NULL) {
+ // debug("COMMAND ERROR*****************************");
+ /* mark this request as never to be completed */
+ end_request(dc);
+
+ debug("command error: %s", gerr->message);
+
+ g_error_free(gerr);
+ BADCONNECTION:
+ /* grab all the rest of the data off the async queue and mark it
+ never to be completed, who knows how long we'll be disconnected */
+ while ((dc = g_async_queue_try_pop(dcc->command_queue)) != NULL) {
+ end_request(dc);
+ }
+
+ g_io_channel_unref(chan);
+
+ SET_CONNECTED_STATE(FALSE);
+
+ /* call the disconnect handler */
+ g_idle_add((GSourceFunc) on_disconnect, dcc);
+
+ break;
+ }
+ }
+
+#undef SET_CONNECTED_STATE
+ }
+
+ return NULL;
+}
+
+/* thread safe */
+gboolean
+dropbox_command_client_is_connected(DropboxCommandClient *dcc) {
+ gboolean command_connected;
+
+ g_mutex_lock(dcc->command_connected_mutex);
+ command_connected = dcc->command_connected;
+ g_mutex_unlock(dcc->command_connected_mutex);
+
+ return command_connected;
+}
+
+/* thread safe */
+void dropbox_command_client_force_reconnect(DropboxCommandClient *dcc) {
+ if (dropbox_command_client_is_connected(dcc) == TRUE) {
+ debug("forcing command to reconnect");
+ dropbox_command_client_request(dcc, (DropboxCommand *) &dropbox_command_client_thread);
+ }
+}
+
+/* thread safe */
+void
+dropbox_command_client_request(DropboxCommandClient *dcc, DropboxCommand *dc) {
+ g_async_queue_push(dcc->command_queue, dc);
+}
+
+/* should only be called once on initialization */
+void
+dropbox_command_client_setup(DropboxCommandClient *dcc) {
+ dcc->command_queue = g_async_queue_new();
+ dcc->command_connected_mutex = g_mutex_new();
+ dcc->command_connected = FALSE;
+ dcc->ca_hooklist = NULL;
+
+ g_hook_list_init(&(dcc->ondisconnect_hooklist), sizeof(GHook));
+ g_hook_list_init(&(dcc->onconnect_hooklist), sizeof(GHook));
+}
+
+void
+dropbox_command_client_add_on_disconnect_hook(DropboxCommandClient *dcc,
+ DropboxCommandClientConnectHook dhcch,
+ gpointer ud) {
+ GHook *newhook;
+
+ newhook = g_hook_alloc(&(dcc->ondisconnect_hooklist));
+ newhook->func = dhcch;
+ newhook->data = ud;
+
+ g_hook_append(&(dcc->ondisconnect_hooklist), newhook);
+}
+
+void
+dropbox_command_client_add_on_connect_hook(DropboxCommandClient *dcc,
+ DropboxCommandClientConnectHook dhcch,
+ gpointer ud) {
+ GHook *newhook;
+
+ newhook = g_hook_alloc(&(dcc->onconnect_hooklist));
+ newhook->func = dhcch;
+ newhook->data = ud;
+
+ g_hook_append(&(dcc->onconnect_hooklist), newhook);
+}
+
+void
+dropbox_command_client_add_connection_attempt_hook(DropboxCommandClient *dcc,
+ DropboxCommandClientConnectionAttemptHook dhcch,
+ gpointer ud) {
+ DropboxCommandClientConnectionAttempt *newhook;
+
+ debug("shouldn't be here...");
+
+ newhook = g_new(DropboxCommandClientConnectionAttempt, 1);
+ newhook->h = dhcch;
+ newhook->ud = ud;
+
+ dcc->ca_hooklist = g_list_append(dcc->ca_hooklist, newhook);
+}
+
+/* should only be called once on initialization */
+void
+dropbox_command_client_start(DropboxCommandClient *dcc) {
+ /* setup the connect to the command server */
+ debug("starting command thread");
+ g_thread_create((gpointer (*)(gpointer data)) dropbox_command_client_thread,
+ dcc, FALSE, NULL);
+}
+
+/* thread safe */
+void dropbox_command_client_send_simple_command(DropboxCommandClient *dcc,
+ const char *command) {
+ DropboxGeneralCommand *dgc;
+
+ dgc = g_new(DropboxGeneralCommand, 1);
+
+ dgc->dc.request_type = GENERAL_COMMAND;
+ dgc->command_name = g_strdup(command);
+ dgc->command_args = NULL;
+ dgc->handler = NULL;
+ dgc->handler_ud = NULL;
+
+ dropbox_command_client_request(dcc, (DropboxCommand *) dgc);
+}
+
+/* thread safe */
+/* this is the C API, there is another send_command_to_db
+ that is more the actual over the wire command */
+void dropbox_command_client_send_command(DropboxCommandClient *dcc,
+ NautilusDropboxCommandResponseHandler h,
+ gpointer ud,
+ const char *command, ...) {
+ va_list ap;
+ DropboxGeneralCommand *dgc;
+ gchar *na;
+ va_start(ap, command);
+
+ dgc = g_new(DropboxGeneralCommand, 1);
+ dgc->dc.request_type = GENERAL_COMMAND;
+ dgc->command_name = g_strdup(command);
+ dgc->command_args = g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_strfreev);
+ /*
+ * NB: The handler is called in the DropboxCommandClient Thread. If you need
+ * it in the main thread you must call g_idle_add in the callback.
+ */
+ dgc->handler = h;
+ dgc->handler_ud = ud;
+
+ while ((na = va_arg(ap, char *)) != NULL) {
+ gchar **is_active_arg;
+
+ is_active_arg = g_new(gchar *, 2);
+
+ g_hash_table_insert(dgc->command_args,
+ g_strdup(na), is_active_arg);
+
+ is_active_arg[0] = g_strdup(va_arg(ap, char *));
+ is_active_arg[1] = NULL;
+ }
+ va_end(ap);
+
+ dropbox_command_client_request(dcc, (DropboxCommand *) dgc);
+}
diff --git a/src/dropbox-command-client.h b/src/dropbox-command-client.h
new file mode 100644
index 0000000..c1ea3bc
--- /dev/null
+++ b/src/dropbox-command-client.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * dropbox-command-client.h
+ * Header file for nautilus-dropbox-command.c
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DROPBOX_COMMAND_CLIENT_H
+#define DROPBOX_COMMAND_CLIENT_H
+
+#include <libnautilus-extension/nautilus-info-provider.h>
+#include <libnautilus-extension/nautilus-file-info.h>
+
+G_BEGIN_DECLS
+
+/* command structs */
+typedef enum {GET_FILE_INFO, GENERAL_COMMAND} NautilusDropboxRequestType;
+
+typedef struct {
+ NautilusDropboxRequestType request_type;
+} DropboxCommand;
+
+typedef struct {
+ DropboxCommand dc;
+ NautilusInfoProvider *provider;
+ GClosure *update_complete;
+ NautilusFileInfo *file;
+ gboolean cancelled;
+} DropboxFileInfoCommand;
+
+typedef struct {
+ DropboxFileInfoCommand *dfic;
+ GHashTable *file_status_response;
+ GHashTable *folder_tag_response;
+ GHashTable *emblems_response;
+} DropboxFileInfoCommandResponse;
+
+typedef void (*NautilusDropboxCommandResponseHandler)(GHashTable *, gpointer);
+
+typedef struct {
+ DropboxCommand dc;
+ gchar *command_name;
+ GHashTable *command_args;
+ NautilusDropboxCommandResponseHandler handler;
+ gpointer handler_ud;
+} DropboxGeneralCommand;
+
+typedef void (*DropboxCommandClientConnectionAttemptHook)(guint, gpointer);
+typedef GHookFunc DropboxCommandClientConnectHook;
+
+typedef struct {
+ GMutex *command_connected_mutex;
+ gboolean command_connected;
+ GAsyncQueue *command_queue;
+ GList *ca_hooklist;
+ GHookList onconnect_hooklist;
+ GHookList ondisconnect_hooklist;
+} DropboxCommandClient;
+
+gboolean dropbox_command_client_is_connected(DropboxCommandClient *dcc);
+
+void dropbox_command_client_force_reconnect(DropboxCommandClient *dcc);
+
+void
+dropbox_command_client_request(DropboxCommandClient *dcc, DropboxCommand *dc);
+
+void
+dropbox_command_client_setup(DropboxCommandClient *dcc);
+
+void
+dropbox_command_client_start(DropboxCommandClient *dcc);
+
+void dropbox_command_client_send_simple_command(DropboxCommandClient *dcc,
+ const char *command);
+
+void dropbox_command_client_send_command(DropboxCommandClient *dcc,
+ NautilusDropboxCommandResponseHandler h,
+ gpointer ud,
+ const char *command, ...);
+void
+dropbox_command_client_add_on_connect_hook(DropboxCommandClient *dcc,
+ DropboxCommandClientConnectHook dhcch,
+ gpointer ud);
+
+void
+dropbox_command_client_add_on_disconnect_hook(DropboxCommandClient *dcc,
+ DropboxCommandClientConnectHook dhcch,
+ gpointer ud);
+
+void
+dropbox_command_client_add_connection_attempt_hook(DropboxCommandClient *dcc,
+ DropboxCommandClientConnectionAttemptHook dhcch,
+ gpointer ud);
+
+G_END_DECLS
+
+#endif
diff --git a/src/dropbox.c b/src/dropbox.c
new file mode 100644
index 0000000..0d59559
--- /dev/null
+++ b/src/dropbox.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * dropbox.c
+ * Nautilus module registering functions for the Dropbox extension.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib-object.h>
+
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include "nautilus-dropbox.h"
+
+static GType type_list[1];
+
+void
+nautilus_module_initialize (GTypeModule *module) {
+ g_print ("Initializing %s\n", PACKAGE_STRING);
+
+ nautilus_dropbox_register_type (module);
+ type_list[0] = NAUTILUS_TYPE_DROPBOX;
+
+ dropbox_use_nautilus_submenu_workaround
+ = (NAUTILUS_VERSION_MAJOR < 2 ||
+ (NAUTILUS_VERSION_MAJOR == 2 && NAUTILUS_VERSION_MINOR <= 22));
+ dropbox_use_operation_in_progress_workaround = TRUE;
+}
+
+void
+nautilus_module_shutdown (void) {
+ g_print ("Shutting down dropbox extension\n");
+}
+
+void
+nautilus_module_list_types (const GType **types,
+ int *num_types) {
+ *types = type_list;
+ *num_types = G_N_ELEMENTS (type_list);
+}
diff --git a/src/g-util.h b/src/g-util.h
new file mode 100644
index 0000000..73d3d81
--- /dev/null
+++ b/src/g-util.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * g-util.h
+ * Helper macros.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef G_UTIL_H
+#define G_UTIL_H
+
+#include <glib.h>
+#include <glib/gprintf.h>
+
+G_BEGIN_DECLS
+
+#ifdef ND_DEBUG
+
+#define debug_enter() {g_print("Entering "); g_print(__FUNCTION__); g_printf("\n");}
+#define debug(format, ...) {g_print(__FUNCTION__); g_print(": "); \
+ g_printf(format, ## __VA_ARGS__); g_print("\n");}
+#define debug_return(v) {g_print("Exiting "); g_print(__FUNCTION__); g_printf("\n"); return v;}
+
+#else
+
+#define debug_enter() do {} while(0)
+#define debug(format, ...) do {} while(0)
+#define debug_return(v) do {} while(0)
+
+#endif
+
+G_END_DECLS
+
+#endif
diff --git a/src/nautilus-dropbox-hooks.c b/src/nautilus-dropbox-hooks.c
new file mode 100644
index 0000000..f37dbbb
--- /dev/null
+++ b/src/nautilus-dropbox-hooks.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * nautilus-dropbox-hooks.c
+ * Implements connection handling and C interface for the Dropbox hook socket.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <string.h>
+
+#include <glib.h>
+
+#include "g-util.h"
+#include "async-io-coroutine.h"
+#include "dropbox-client-util.h"
+#include "nautilus-dropbox-hooks.h"
+
+typedef struct {
+ DropboxUpdateHook hook;
+ gpointer ud;
+} HookData;
+
+static gboolean
+try_to_connect(NautilusDropboxHookserv *hookserv);
+
+static gboolean
+handle_hook_server_input(GIOChannel *chan,
+ GIOCondition cond,
+ NautilusDropboxHookserv *hookserv) {
+ /*debug_enter(); */
+
+ /* we have some sweet macros defined that allow us to write this
+ async event handler like a microthread yeahh, watch out for context */
+ CRBEGIN(hookserv->hhsi.line);
+ while (1) {
+ hookserv->hhsi.command_args =
+ g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_strfreev);
+ hookserv->hhsi.numargs = 0;
+
+ /* read the command name */
+ {
+ gchar *line;
+ CRREADLINE(hookserv->hhsi.line, chan, line);
+ hookserv->hhsi.command_name = dropbox_client_util_desanitize(line);
+ g_free(line);
+ }
+
+ /*debug("got a hook name: %s", hookserv->hhsi.command_name); */
+
+ /* now read each arg line (until a certain limit) until we receive "done" */
+ while (1) {
+ gchar *line;
+
+ /* if too many arguments, this connection seems malicious */
+ if (hookserv->hhsi.numargs >= 20) {
+ CRHALT;
+ }
+
+ CRREADLINE(hookserv->hhsi.line, chan, line);
+
+ if (strcmp("done", line) == 0) {
+ g_free(line);
+ break;
+ }
+ else {
+ gboolean parse_result;
+
+ parse_result =
+ dropbox_client_util_command_parse_arg(line,
+ hookserv->hhsi.command_args);
+ g_free(line);
+
+ if (FALSE == parse_result) {
+ debug("bad parse");
+ CRHALT;
+ }
+ }
+
+ hookserv->hhsi.numargs += 1;
+ }
+
+ {
+ HookData *hd;
+ hd = (HookData *)
+ g_hash_table_lookup(hookserv->dispatch_table,
+ hookserv->hhsi.command_name);
+ if (hd != NULL) {
+ (hd->hook)(hookserv->hhsi.command_args, hd->ud);
+ }
+ }
+
+ g_free(hookserv->hhsi.command_name);
+ g_hash_table_unref(hookserv->hhsi.command_args);
+ hookserv->hhsi.command_name = NULL;
+ hookserv->hhsi.command_args = NULL;
+ }
+ CREND;
+}
+
+static void
+watch_killer(NautilusDropboxHookserv *hookserv) {
+ debug("hook client disconnected");
+
+ hookserv->connected = FALSE;
+
+ g_hook_list_invoke(&(hookserv->ondisconnect_hooklist), FALSE);
+
+ /* we basically just have to free the memory allocated in the
+ handle_hook_server_init ctx */
+ if (hookserv->hhsi.command_name != NULL) {
+ g_free(hookserv->hhsi.command_name);
+ hookserv->hhsi.command_name = NULL;
+ }
+
+ if (hookserv->hhsi.command_args != NULL) {
+ g_hash_table_unref(hookserv->hhsi.command_args);
+ hookserv->hhsi.command_args = NULL;
+ }
+
+ g_io_channel_unref(hookserv->chan);
+ hookserv->chan = NULL;
+ hookserv->event_source = 0;
+ hookserv->socket = 0;
+
+ /* lol we also have to start a new connection */
+ try_to_connect(hookserv);
+}
+
+static gboolean
+try_to_connect(NautilusDropboxHookserv *hookserv) {
+ /* create socket */
+ hookserv->socket = socket(PF_UNIX, SOCK_STREAM, 0);
+
+ /* set native non-blocking, for connect timeout */
+ {
+ unsigned int flags;
+
+ if ((flags = fcntl(hookserv->socket, F_GETFL, 0)) < 0) {
+ goto FAIL_CLEANUP;
+ }
+
+ if (fcntl(hookserv->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
+ goto FAIL_CLEANUP;
+ }
+ }
+
+ /* connect to server, might fail of course */
+ {
+ struct sockaddr_un addr;
+ socklen_t addr_len;
+
+ /* intialize address structure */
+ addr.sun_family = AF_UNIX;
+ g_snprintf(addr.sun_path,
+ sizeof(addr.sun_path),
+ "%s/.dropbox/iface_socket",
+ g_get_home_dir());
+ addr_len = sizeof(addr) - sizeof(addr.sun_path) + strlen(addr.sun_path);
+
+ /* if there was an error we have to try again later */
+ if (connect(hookserv->socket, (struct sockaddr *) &addr, addr_len) < 0) {
+ if (errno == EINPROGRESS) {
+ fd_set writers;
+ struct timeval tv = {1, 0};
+ FD_ZERO(&writers);
+ FD_SET(hookserv->socket, &writers);
+
+ /* if nothing was ready after 3 seconds, fail out homie */
+ if (select(hookserv->socket+1, NULL, &writers, NULL, &tv) == 0) {
+ goto FAIL_CLEANUP;
+ }
+
+ if (connect(hookserv->socket, (struct sockaddr *) &addr, addr_len) < 0) {
+ debug("couldn't connect to hook server after 1 second");
+ goto FAIL_CLEANUP;
+ }
+ }
+ else {
+ goto FAIL_CLEANUP;
+ }
+ }
+ }
+
+ /* lol sometimes i write funny codez */
+ if (FALSE) {
+ FAIL_CLEANUP:
+ close(hookserv->socket);
+ g_timeout_add_seconds(1, (GSourceFunc) try_to_connect, hookserv);
+ return FALSE;
+ }
+
+ /* great we connected!, let's create the channel and wait on it */
+ hookserv->chan = g_io_channel_unix_new(hookserv->socket);
+ g_io_channel_set_line_term(hookserv->chan, "\n", -1);
+ g_io_channel_set_close_on_unref(hookserv->chan, TRUE);
+
+ /*debug("create channel"); */
+
+ /* Set non-blocking ;) (again just in case) */
+ {
+ GIOFlags flags;
+ GIOStatus iostat;
+
+ flags = g_io_channel_get_flags(hookserv->chan);
+ iostat = g_io_channel_set_flags(hookserv->chan, flags | G_IO_FLAG_NONBLOCK,
+ NULL);
+ if (iostat == G_IO_STATUS_ERROR) {
+ g_io_channel_unref(hookserv->chan);
+ g_timeout_add_seconds(1, (GSourceFunc) try_to_connect, hookserv);
+ return FALSE;
+ }
+ }
+
+ /*debug("set non blocking"); */
+
+ /* this is fun, async io watcher */
+ hookserv->hhsi.line = 0;
+ hookserv->hhsi.command_args = NULL;
+ hookserv->hhsi.command_name = NULL;
+ hookserv->event_source =
+ g_io_add_watch_full(hookserv->chan, G_PRIORITY_DEFAULT,
+ G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) handle_hook_server_input, hookserv,
+ (GDestroyNotify) watch_killer);
+
+ debug("hook client connected");
+ hookserv->connected = TRUE;
+ g_hook_list_invoke(&(hookserv->onconnect_hooklist), FALSE);
+
+ /*debug("added watch");*/
+ return FALSE;
+}
+
+/* should only be called in glib main loop */
+/* returns a gboolean because it is a GSourceFunc */
+gboolean nautilus_dropbox_hooks_force_reconnect(NautilusDropboxHookserv *hookserv) {
+ debug_enter();
+
+ if (hookserv->connected == FALSE) {
+ return FALSE;
+ }
+
+ debug("forcing hook to reconnect");
+
+ g_assert(hookserv->event_source >= 0);
+
+ if (hookserv->event_source > 0) {
+ g_source_remove(hookserv->event_source);
+ }
+ else if (hookserv->event_source == 0) {
+ debug("event source was zero!!!!!");
+ }
+
+ return FALSE;
+}
+
+gboolean
+nautilus_dropbox_hooks_is_connected(NautilusDropboxHookserv *hookserv) {
+ return hookserv->connected;
+}
+
+void
+nautilus_dropbox_hooks_setup(NautilusDropboxHookserv *hookserv) {
+ hookserv->dispatch_table = g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ g_free, g_free);
+ hookserv->connected = FALSE;
+
+ g_hook_list_init(&(hookserv->ondisconnect_hooklist), sizeof(GHook));
+ g_hook_list_init(&(hookserv->onconnect_hooklist), sizeof(GHook));
+}
+
+void
+nautilus_dropbox_hooks_add_on_disconnect_hook(NautilusDropboxHookserv *hookserv,
+ DropboxHookClientConnectHook dhcch,
+ gpointer ud) {
+ GHook *newhook;
+
+ newhook = g_hook_alloc(&(hookserv->ondisconnect_hooklist));
+ newhook->func = dhcch;
+ newhook->data = ud;
+
+ g_hook_append(&(hookserv->ondisconnect_hooklist), newhook);
+}
+
+void
+nautilus_dropbox_hooks_add_on_connect_hook(NautilusDropboxHookserv *hookserv,
+ DropboxHookClientConnectHook dhcch,
+ gpointer ud) {
+ GHook *newhook;
+
+ newhook = g_hook_alloc(&(hookserv->onconnect_hooklist));
+ newhook->func = dhcch;
+ newhook->data = ud;
+
+ g_hook_append(&(hookserv->onconnect_hooklist), newhook);
+}
+
+void nautilus_dropbox_hooks_add(NautilusDropboxHookserv *ndhs,
+ const gchar *hook_name,
+ DropboxUpdateHook hook, gpointer ud) {
+ HookData *hd;
+ hd = g_new(HookData, 1);
+ hd->hook = hook;
+ hd->ud = ud;
+ g_hash_table_insert(ndhs->dispatch_table, g_strdup(hook_name), hd);
+}
+
+void
+nautilus_dropbox_hooks_start(NautilusDropboxHookserv *hookserv) {
+ try_to_connect(hookserv);
+}
diff --git a/src/nautilus-dropbox-hooks.h b/src/nautilus-dropbox-hooks.h
new file mode 100644
index 0000000..fb69c3b
--- /dev/null
+++ b/src/nautilus-dropbox-hooks.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * nautilus-dropbox-hooks.h
+ * Header file for nautilus-dropbox-hooks.c
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NAUTILUS_DROPBOX_HOOKS_H
+#define NAUTILUS_DROPBOX_HOOKS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef void (*DropboxUpdateHook)(GHashTable *, gpointer);
+typedef void (*DropboxHookClientConnectHook)(gpointer);
+
+typedef struct {
+ GIOChannel *chan;
+ int socket;
+ struct {
+ int line;
+ gchar *command_name;
+ GHashTable *command_args;
+ int numargs;
+ } hhsi;
+ gboolean connected;
+ guint event_source;
+ GHashTable *dispatch_table;
+ GHookList ondisconnect_hooklist;
+ GHookList onconnect_hooklist;
+} NautilusDropboxHookserv;
+
+void
+nautilus_dropbox_hooks_setup(NautilusDropboxHookserv *);
+
+void
+nautilus_dropbox_hooks_start(NautilusDropboxHookserv *);
+
+gboolean
+nautilus_dropbox_hooks_is_connected(NautilusDropboxHookserv *);
+
+gboolean
+nautilus_dropbox_hooks_force_reconnect(NautilusDropboxHookserv *);
+
+void
+nautilus_dropbox_hooks_add(NautilusDropboxHookserv *ndhs,
+ const gchar *hook_name,
+ DropboxUpdateHook hook, gpointer ud);
+void
+nautilus_dropbox_hooks_add_on_disconnect_hook(NautilusDropboxHookserv *hookserv,
+ DropboxHookClientConnectHook dhcch,
+ gpointer ud);
+
+void
+nautilus_dropbox_hooks_add_on_connect_hook(NautilusDropboxHookserv *hookserv,
+ DropboxHookClientConnectHook dhcch,
+ gpointer ud);
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/nautilus-dropbox.c b/src/nautilus-dropbox.c
new file mode 100644
index 0000000..86a0e8a
--- /dev/null
+++ b/src/nautilus-dropbox.c
@@ -0,0 +1,960 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * nautilus-dropbox.c
+ * Implements the Nautilus extension API for Dropbox.
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h> /* for GETTEXT_PACKAGE */
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <glib/gprintf.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include <libnautilus-extension/nautilus-extension-types.h>
+#include <libnautilus-extension/nautilus-menu-provider.h>
+#include <libnautilus-extension/nautilus-info-provider.h>
+
+#include "g-util.h"
+#include "dropbox-command-client.h"
+#include "nautilus-dropbox.h"
+#include "nautilus-dropbox-hooks.h"
+
+static char *emblems[] = {"dropbox-uptodate", "dropbox-syncing", "dropbox-unsyncable"};
+gchar *DEFAULT_EMBLEM_PATHS[2] = { EMBLEMDIR , NULL };
+
+gboolean dropbox_use_nautilus_submenu_workaround;
+gboolean dropbox_use_operation_in_progress_workaround;
+
+static GType dropbox_type = 0;
+
+/* for old versions of glib */
+#if 0 // Silence Warnings.
+static void my_g_hash_table_get_keys_helper(gpointer key,
+ gpointer value,
+ GList **ud) {
+ *ud = g_list_append(*ud, key);
+}
+
+static GList *my_g_hash_table_get_keys(GHashTable *ght) {
+ GList *list = NULL;
+ g_hash_table_foreach(ght, (GHFunc) my_g_hash_table_get_keys_helper, &list);
+ return list;
+}
+#endif
+
+/* probably my favorite function */
+static gchar *
+canonicalize_path(gchar *path) {
+ int i, j = 0;
+ gchar *toret, **cpy, **elts;
+
+ g_assert(path != NULL);
+ g_assert(path[0] == '/');
+
+ elts = g_strsplit(path, "/", 0);
+ cpy = g_new(gchar *, g_strv_length(elts)+1);
+ cpy[j++] = "/";
+ for (i = 0; elts[i] != NULL; i++) {
+ if (strcmp(elts[i], "..") == 0) {
+ j--;
+ }
+ else if (strcmp(elts[i], ".") != 0 && elts[i][0] != '\0') {
+ cpy[j++] = elts[i];
+ }
+ }
+
+ cpy[j] = NULL;
+ toret = g_build_filenamev(cpy);
+ g_free(cpy);
+ g_strfreev(elts);
+
+ return toret;
+}
+
+static void
+reset_file(NautilusFileInfo *file) {
+ debug("resetting file %p", (void *) file);
+ nautilus_file_info_invalidate_extension_info(file);
+}
+
+gboolean
+reset_all_files(NautilusDropbox *cvs) {
+ /* Only run this on the main loop or you'll cause problems. */
+
+ /* this works because you can call a function pointer with
+ more arguments than it takes */
+ g_hash_table_foreach(cvs->obj2filename, (GHFunc) reset_file, NULL);
+ return FALSE;
+}
+
+
+static void
+when_file_dies(NautilusDropbox *cvs, NautilusFileInfo *address) {
+ gchar *filename;
+
+ filename = g_hash_table_lookup(cvs->obj2filename, address);
+
+ /* we never got a change to view this file */
+ if (filename == NULL) {
+ return;
+ }
+
+ /* too chatty */
+ /* debug("removing %s <-> 0x%p", filename, address); */
+
+ g_hash_table_remove(cvs->filename2obj, filename);
+ g_hash_table_remove(cvs->obj2filename, address);
+}
+
+static void
+changed_cb(NautilusFileInfo *file, NautilusDropbox *cvs) {
+ /* check if this file's path has changed, if so update the hash and invalidate
+ the file */
+ gchar *filename, *pfilename;
+ gchar *filename2;
+ gchar *uri;
+
+ uri = nautilus_file_info_get_uri(file);
+ pfilename = g_filename_from_uri(uri, NULL, NULL);
+ filename = pfilename ? canonicalize_path(pfilename) : NULL;
+ filename2 = g_hash_table_lookup(cvs->obj2filename, file);
+
+ g_free(pfilename);
+ g_free(uri);
+
+ /* if filename2 is NULL we've never seen this file in update_file_info */
+ if (filename2 == NULL) {
+ g_free(filename);
+ return;
+ }
+
+ if (filename == NULL) {
+ /* A file has moved to offline storage. Lets remove it from our tables. */
+ g_object_weak_unref(G_OBJECT(file), (GWeakNotify) when_file_dies, cvs);
+ g_hash_table_remove(cvs->filename2obj, filename2);
+ g_hash_table_remove(cvs->obj2filename, file);
+ g_signal_handlers_disconnect_by_func(file, G_CALLBACK(changed_cb), cvs);
+ reset_file(file);
+ return;
+ }
+
+ /* this is a hack, because nautilus doesn't do this for us, for some reason
+ the file's path has changed */
+ if (strcmp(filename, filename2) != 0) {
+ debug("shifty old: %s, new %s", filename2, filename);
+
+ /* gotta do this first, the call after this frees filename2 */
+ g_hash_table_remove(cvs->filename2obj, filename2);
+
+ g_hash_table_replace(cvs->obj2filename, file, g_strdup(filename));
+
+ {
+ NautilusFileInfo *f2;
+ /* we shouldn't have another mapping from filename to an object */
+ f2 = g_hash_table_lookup(cvs->filename2obj, filename);
+ if (f2 != NULL) {
+ /* lets fix it if it's true, just remove the mapping */
+ g_hash_table_remove(cvs->filename2obj, filename);
+ g_hash_table_remove(cvs->obj2filename, f2);
+ }
+ }
+
+ g_hash_table_insert(cvs->filename2obj, g_strdup(filename), file);
+ reset_file(file);
+ }
+
+ g_free(filename);
+}
+
+static NautilusOperationResult
+nautilus_dropbox_update_file_info(NautilusInfoProvider *provider,
+ NautilusFileInfo *file,
+ GClosure *update_complete,
+ NautilusOperationHandle **handle) {
+ NautilusDropbox *cvs;
+
+ cvs = NAUTILUS_DROPBOX(provider);
+
+ /* this code adds this file object to our two-way hash of file objects
+ so we can shell touch these files later */
+ {
+ gchar *pfilename, *uri;
+
+ uri = nautilus_file_info_get_uri(file);
+ pfilename = g_filename_from_uri(uri, NULL, NULL);
+ g_free(uri);
+ if (pfilename == NULL) {
+ return NAUTILUS_OPERATION_COMPLETE;
+ }
+ else {
+ int cmp = 0;
+ gchar *stored_filename;
+ gchar *filename;
+
+ filename = canonicalize_path(pfilename);
+ g_free(pfilename);
+ stored_filename = g_hash_table_lookup(cvs->obj2filename, file);
+
+ /* don't worry about the dup checks, gcc is smart enough to optimize this
+ GCSE ftw */
+ if ((stored_filename != NULL && (cmp = strcmp(stored_filename, filename)) != 0) ||
+ stored_filename == NULL) {
+
+ if (stored_filename != NULL && cmp != 0) {
+ /* this happens when the filename changes name on a file obj
+ but changed_cb isn't called */
+ g_object_weak_unref(G_OBJECT(file), (GWeakNotify) when_file_dies, cvs);
+ g_hash_table_remove(cvs->obj2filename, file);
+ g_hash_table_remove(cvs->filename2obj, stored_filename);
+ g_signal_handlers_disconnect_by_func(file, G_CALLBACK(changed_cb), cvs);
+ }
+ else if (stored_filename == NULL) {
+ NautilusFileInfo *f2;
+
+ if ((f2 = g_hash_table_lookup(cvs->filename2obj, filename)) != NULL) {
+ /* if the filename exists in the filename2obj hash
+ but the file obj doesn't exist in the obj2filename hash:
+
+ this happens when nautilus allocates another file object
+ for a filename without first deleting the original file object
+
+ just remove the association to the older file object, it's obsolete
+ */
+ g_object_weak_unref(G_OBJECT(f2), (GWeakNotify) when_file_dies, cvs);
+ g_signal_handlers_disconnect_by_func(f2, G_CALLBACK(changed_cb), cvs);
+ g_hash_table_remove(cvs->filename2obj, filename);
+ g_hash_table_remove(cvs->obj2filename, f2);
+ }
+ }
+
+ /* too chatty */
+ /* debug("adding %s <-> 0x%p", filename, file);*/
+ g_object_weak_ref(G_OBJECT(file), (GWeakNotify) when_file_dies, cvs);
+ g_hash_table_insert(cvs->filename2obj, g_strdup(filename), file);
+ g_hash_table_insert(cvs->obj2filename, file, g_strdup(filename));
+ g_signal_connect(file, "changed", G_CALLBACK(changed_cb), cvs);
+ }
+
+ g_free(filename);
+ }
+ }
+
+ if (dropbox_client_is_connected(&(cvs->dc)) == FALSE ||
+ nautilus_file_info_is_gone(file)) {
+ return NAUTILUS_OPERATION_COMPLETE;
+ }
+
+ {
+ DropboxFileInfoCommand *dfic = g_new0(DropboxFileInfoCommand, 1);
+
+ dfic->cancelled = FALSE;
+ dfic->provider = provider;
+ dfic->dc.request_type = GET_FILE_INFO;
+ dfic->update_complete = g_closure_ref(update_complete);
+ dfic->file = g_object_ref(file);
+
+ dropbox_command_client_request(&(cvs->dc.dcc), (DropboxCommand *) dfic);
+
+ *handle = (NautilusOperationHandle *) dfic;
+
+ return dropbox_use_operation_in_progress_workaround
+ ? NAUTILUS_OPERATION_COMPLETE
+ : NAUTILUS_OPERATION_IN_PROGRESS;
+ }
+}
+
+static void
+handle_shell_touch(GHashTable *args, NautilusDropbox *cvs) {
+ gchar **path;
+
+ // debug_enter();
+
+ if ((path = g_hash_table_lookup(args, "path")) != NULL &&
+ path[0][0] == '/') {
+ NautilusFileInfo *file;
+ gchar *filename;
+
+ filename = canonicalize_path(path[0]);
+
+ debug("shell touch for %s", filename);
+
+ file = g_hash_table_lookup(cvs->filename2obj, filename);
+
+ if (file != NULL) {
+ debug("gonna reset %s", filename);
+ reset_file(file);
+ }
+ g_free(filename);
+ }
+
+ return;
+}
+
+gboolean
+nautilus_dropbox_finish_file_info_command(DropboxFileInfoCommandResponse *dficr) {
+
+ //debug_enter();
+ NautilusOperationResult result = NAUTILUS_OPERATION_FAILED;
+
+ if (!dficr->dfic->cancelled) {
+ gchar **status = NULL;
+ gboolean isdir;
+
+ isdir = nautilus_file_info_is_directory(dficr->dfic->file) ;
+
+ /* if we have emblems just use them. */
+ if (dficr->emblems_response != NULL &&
+ (status = g_hash_table_lookup(dficr->emblems_response, "emblems")) != NULL) {
+ int i;
+ for ( i = 0; status[i] != NULL; i++) {
+ if (status[i][0])
+ nautilus_file_info_add_emblem(dficr->dfic->file, status[i]);
+ }
+ result = NAUTILUS_OPERATION_COMPLETE;
+ }
+ /* if the file status command went okay */
+ else if ((dficr->file_status_response != NULL &&
+ (status =
+ g_hash_table_lookup(dficr->file_status_response, "status")) != NULL) &&
+ ((isdir == TRUE &&
+ dficr->folder_tag_response != NULL) || isdir == FALSE)) {
+ gchar **tag = NULL;
+
+ /* set the tag emblem */
+ if (isdir &&
+ (tag = g_hash_table_lookup(dficr->folder_tag_response, "tag")) != NULL) {
+ if (strcmp("public", tag[0]) == 0) {
+ nautilus_file_info_add_emblem(dficr->dfic->file, "web");
+ }
+ else if (strcmp("shared", tag[0]) == 0) {
+ nautilus_file_info_add_emblem(dficr->dfic->file, "people");
+ }
+ else if (strcmp("photos", tag[0]) == 0) {
+ nautilus_file_info_add_emblem(dficr->dfic->file, "photos");
+ }
+ else if (strcmp("sandbox", tag[0]) == 0) {
+ nautilus_file_info_add_emblem(dficr->dfic->file, "star");
+ }
+ }
+
+ /* set the status emblem */
+ {
+ int emblem_code = 0;
+
+ if (strcmp("up to date", status[0]) == 0) {
+ emblem_code = 1;
+ }
+ else if (strcmp("syncing", status[0]) == 0) {
+ emblem_code = 2;
+ }
+ else if (strcmp("unsyncable", status[0]) == 0) {
+ emblem_code = 3;
+ }
+
+ if (emblem_code > 0) {
+ /*
+ debug("%s to %s", emblems[emblem_code-1],
+ g_filename_from_uri(nautilus_file_info_get_uri(dficr->dfic->file),
+ NULL, NULL));
+ */
+ nautilus_file_info_add_emblem(dficr->dfic->file, emblems[emblem_code-1]);
+ }
+ }
+ result = NAUTILUS_OPERATION_COMPLETE;
+ }
+ }
+
+ /* complete the info request */
+ if (!dropbox_use_operation_in_progress_workaround) {
+ nautilus_info_provider_update_complete_invoke(dficr->dfic->update_complete,
+ dficr->dfic->provider,
+ (NautilusOperationHandle*) dficr->dfic,
+ result);
+ }
+
+ /* destroy the objects we created */
+ if (dficr->file_status_response != NULL)
+ g_hash_table_unref(dficr->file_status_response);
+ if (dficr->folder_tag_response != NULL)
+ g_hash_table_unref(dficr->folder_tag_response);
+ if (dficr->emblems_response != NULL)
+ g_hash_table_unref(dficr->emblems_response);
+
+ /* unref the objects we didn't create */
+ g_closure_unref(dficr->dfic->update_complete);
+ g_object_unref(dficr->dfic->file);
+
+ /* now free the structs */
+ g_free(dficr->dfic);
+ g_free(dficr);
+
+ return FALSE;
+}
+
+static void
+nautilus_dropbox_cancel_update(NautilusInfoProvider *provider,
+ NautilusOperationHandle *handle) {
+ DropboxFileInfoCommand *dfic = (DropboxFileInfoCommand *) handle;
+ dfic->cancelled = TRUE;
+ return;
+}
+
+static void
+menu_item_cb(NautilusMenuItem *item,
+ NautilusDropbox *cvs) {
+ gchar *verb;
+ GList *files;
+ DropboxGeneralCommand *dcac;
+
+ dcac = g_new(DropboxGeneralCommand, 1);
+
+ /* maybe these would be better passed in a container
+ struct used as the userdata pointer, oh well this
+ is how dave camp does it */
+ files = g_object_get_data(G_OBJECT(item), "nautilus_dropbox_files");
+ verb = g_object_get_data(G_OBJECT(item), "nautilus_dropbox_verb");
+
+ dcac->dc.request_type = GENERAL_COMMAND;
+
+ /* build the argument list */
+ dcac->command_args = g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_strfreev);
+ {
+ gchar **arglist;
+ guint i;
+ GList *li;
+
+ arglist = g_new0(gchar *,g_list_length(files) + 1);
+
+ for (li = files, i = 0; li != NULL; li = g_list_next(li)) {
+ char *uri = nautilus_file_info_get_uri(NAUTILUS_FILE_INFO(li->data));
+ char *path = g_filename_from_uri(uri, NULL, NULL);
+ g_free(uri);
+ if (!path)
+ continue;
+ arglist[i] = path;
+ i++;
+ }
+
+ g_hash_table_insert(dcac->command_args,
+ g_strdup("paths"),
+ arglist);
+ }
+
+ {
+ gchar **arglist;
+ arglist = g_new(gchar *, 2);
+ arglist[0] = g_strdup(verb);
+ arglist[1] = NULL;
+ g_hash_table_insert(dcac->command_args, g_strdup("verb"), arglist);
+ }
+
+ dcac->command_name = g_strdup("icon_overlay_context_action");
+ dcac->handler = NULL;
+ dcac->handler_ud = NULL;
+
+ dropbox_command_client_request(&(cvs->dc.dcc), (DropboxCommand *) dcac);
+}
+
+static char from_hex(gchar ch) {
+ return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
+}
+
+// decode in --> out, but dont fill more than n chars into out
+// returns len of out if thing went well, -1 if n wasn't big enough
+// can be used in place (whoa!)
+int GhettoURLDecode(gchar* out, gchar* in, int n) {
+ char *out_initial;
+
+ for(out_initial = out; out-out_initial < n && *in != '\0'; out++) {
+ if (*in == '%') {
+ *out = from_hex(in[1]) << 4 | from_hex(in[2]);
+ in += 3;
+ }
+ else {
+ *out = *in;
+ in++;
+ }
+ }
+
+ if (out-out_initial < n) {
+ *out = '\0';
+ return out-out_initial;
+ }
+ return -1;
+}
+
+static int
+nautilus_dropbox_parse_menu(gchar **options,
+ NautilusMenu *menu,
+ GString *old_action_string,
+ GList *toret,
+ NautilusMenuProvider *provider,
+ GList *files)
+{
+ int ret = 0;
+ int i;
+
+ for ( i = 0; options[i] != NULL; i++) {
+ gchar **option_info = g_strsplit(options[i], "~", 3);
+ /* if this is a valid string */
+ if (option_info[0] == NULL || option_info[1] == NULL ||
+ option_info[2] == NULL || option_info[3] != NULL) {
+ g_strfreev(option_info);
+ continue;
+ }
+
+ gchar* item_name = option_info[0];
+ gchar* item_inner = option_info[1];
+ gchar* verb = option_info[2];
+
+ GhettoURLDecode(item_name, item_name, strlen(item_name));
+ GhettoURLDecode(verb, verb, strlen(verb));
+ GhettoURLDecode(item_inner, item_inner, strlen(item_inner));
+
+ // If the inner section has a menu in it then we create a submenu. The verb will be ignored.
+ // Otherwise add the verb to our map and add the menu item to the list.
+ if (strchr(item_inner, '~') != NULL) {
+ GString *new_action_string = g_string_new(old_action_string->str);
+ gchar **suboptions = g_strsplit(item_inner, "|", -1);
+ NautilusMenuItem *item;
+ NautilusMenu *submenu = nautilus_menu_new();
+
+ g_string_append(new_action_string, item_name);
+ g_string_append(new_action_string, "::");
+
+ ret += nautilus_dropbox_parse_menu(suboptions, submenu, new_action_string,
+ toret, provider, files);
+
+ item = nautilus_menu_item_new(new_action_string->str,
+ item_name, "", NULL);
+ nautilus_menu_item_set_submenu(item, submenu);
+ nautilus_menu_append_item(menu, item);
+
+ g_strfreev(suboptions);
+ g_object_unref(item);
+ g_object_unref(submenu);
+ g_string_free(new_action_string, TRUE);
+ } else {
+ NautilusMenuItem *item;
+ GString *new_action_string = g_string_new(old_action_string->str);
+ gboolean grayed_out = FALSE;
+
+ g_string_append(new_action_string, verb);
+
+ if (item_name[0] == '!') {
+ item_name++;
+ grayed_out = TRUE;
+ }
+
+ item = nautilus_menu_item_new(new_action_string->str, item_name, item_inner, NULL);
+
+ nautilus_menu_append_item(menu, item);
+ /* add the file metadata to this item */
+ g_object_set_data_full (G_OBJECT(item), "nautilus_dropbox_files",
+ nautilus_file_info_list_copy (files),
+ (GDestroyNotify) nautilus_file_info_list_free);
+ /* add the verb metadata */
+ g_object_set_data_full (G_OBJECT(item), "nautilus_dropbox_verb",
+ g_strdup(verb),
+ (GDestroyNotify) g_free);
+ g_signal_connect (item, "activate", G_CALLBACK (menu_item_cb), provider);
+
+ if (grayed_out) {
+ GValue sensitive = { 0 };
+ g_value_init (&sensitive, G_TYPE_BOOLEAN);
+ g_value_set_boolean (&sensitive, FALSE);
+ g_object_set_property (G_OBJECT(item), "sensitive", &sensitive);
+ }
+
+ /* taken from nautilus-file-repairer (http://repairer.kldp.net/):
+ * this code is a workaround for a bug of nautilus
+ * See: http://bugzilla.gnome.org/show_bug.cgi?id=508878 */
+ if (dropbox_use_nautilus_submenu_workaround) {
+ toret = g_list_append(toret, item);
+ }
+
+ g_object_unref(item);
+ g_string_free(new_action_string, TRUE);
+ ret++;
+ }
+ g_strfreev(option_info);
+ }
+ return ret;
+}
+
+static void
+get_file_items_callback(GHashTable *response, gpointer ud)
+{
+ GAsyncQueue *reply_queue = ud;
+
+ /* queue_push doesn't accept NULL as a value so we create an empty hash table
+ * if we got no response. */
+ g_async_queue_push(reply_queue, response ? g_hash_table_ref(response) :
+ g_hash_table_new((GHashFunc) g_str_hash, (GEqualFunc) g_str_equal));
+ g_async_queue_unref(reply_queue);
+}
+
+
+static GList *
+nautilus_dropbox_get_file_items(NautilusMenuProvider *provider,
+ GtkWidget *window,
+ GList *files)
+{
+ /*
+ * 1. Convert files to filenames.
+ */
+ int file_count = g_list_length(files);
+
+ if (file_count < 1)
+ return NULL;
+
+ gchar **paths = g_new0(gchar *, file_count + 1);
+ int i = 0;
+ GList* elem;
+
+ for (elem = files; elem; elem = elem->next, i++) {
+ gchar *uri = nautilus_file_info_get_uri(elem->data);
+ gchar *filename_un = uri ? g_filename_from_uri(uri, NULL, NULL) : NULL;
+ gchar *filename = filename_un ? g_filename_to_utf8(filename_un, -1, NULL, NULL, NULL) : NULL;
+
+ g_free(uri);
+ g_free(filename_un);
+
+ if (filename == NULL) {
+ /* oooh, filename wasn't correctly encoded, or isn't a local file. */
+ g_strfreev(paths);
+ return NULL;
+ }
+
+ paths[i] = filename;
+ }
+
+ GAsyncQueue *reply_queue = g_async_queue_new_full((GDestroyNotify)g_hash_table_unref);
+
+ /*
+ * 2. Create a DropboxGeneralCommand to call "icon_overlay_context_options"
+ */
+
+ DropboxGeneralCommand *dgc = g_new0(DropboxGeneralCommand, 1);
+ dgc->dc.request_type = GENERAL_COMMAND;
+ dgc->command_name = g_strdup("icon_overlay_context_options");
+ dgc->command_args = g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_strfreev);
+ g_hash_table_insert(dgc->command_args, g_strdup("paths"), paths);
+ dgc->handler = get_file_items_callback;
+ dgc->handler_ud = g_async_queue_ref(reply_queue);
+
+ /*
+ * 3. Queue it up for the helper thread to run it.
+ */
+ NautilusDropbox *cvs = NAUTILUS_DROPBOX(provider);
+ dropbox_command_client_request(&(cvs->dc.dcc), (DropboxCommand *) dgc);
+
+ GTimeVal gtv;
+
+ /*
+ * 4. We have to block until it's done because nautilus expects a reply. But we will
+ * only block for 50 ms for a reply.
+ */
+
+ g_get_current_time(&gtv);
+ g_time_val_add(&gtv, 50000);
+
+ GHashTable *context_options_response = g_async_queue_timed_pop(reply_queue, &gtv);
+ g_async_queue_unref(reply_queue);
+
+ if (!context_options_response) {
+ return NULL;
+ }
+
+ /*
+ * 5. Parse the reply.
+ */
+
+ char **options = g_hash_table_lookup(context_options_response, "options");
+ GList *toret = NULL;
+
+ if (options && *options && **options) {
+ /* build the menu */
+ NautilusMenuItem *root_item;
+ NautilusMenu *root_menu;
+
+ root_menu = nautilus_menu_new();
+ root_item = nautilus_menu_item_new("NautilusDropbox::root_item",
+ "Dropbox", "Dropbox Options", "dropbox");
+
+ toret = g_list_append(toret, root_item);
+ GString *action_string = g_string_new("NautilusDropbox::");
+
+ if (!nautilus_dropbox_parse_menu(options, root_menu, action_string,
+ toret, provider, files)) {
+ g_object_unref(toret);
+ toret = NULL;
+ }
+
+ nautilus_menu_item_set_submenu(root_item, root_menu);
+
+ g_string_free(action_string, TRUE);
+ g_object_unref(root_menu);
+ }
+
+ g_hash_table_unref(context_options_response);
+
+ return toret;
+}
+
+gboolean
+add_emblem_paths(GHashTable* emblem_paths_response)
+{
+ /* Only run this on the main loop or you'll cause problems. */
+ if (!emblem_paths_response)
+ return FALSE;
+
+ gchar **emblem_paths_list;
+ int i;
+
+ GtkIconTheme *theme = gtk_icon_theme_get_default();
+
+ if (emblem_paths_response &&
+ (emblem_paths_list = g_hash_table_lookup(emblem_paths_response, "path"))) {
+ for (i = 0; emblem_paths_list[i] != NULL; i++) {
+ if (emblem_paths_list[i][0])
+ gtk_icon_theme_append_search_path(theme, emblem_paths_list[i]);
+ }
+ }
+ g_hash_table_unref(emblem_paths_response);
+ return FALSE;
+}
+
+gboolean
+remove_emblem_paths(GHashTable* emblem_paths_response)
+{
+ /* Only run this on the main loop or you'll cause problems. */
+ if (!emblem_paths_response)
+ return FALSE;
+
+ gchar **emblem_paths_list = g_hash_table_lookup(emblem_paths_response, "path");
+ if (!emblem_paths_list)
+ goto exit;
+
+ // We need to remove the old paths.
+ GtkIconTheme * icon_theme = gtk_icon_theme_get_default();
+ gchar ** paths;
+ gint path_count;
+
+ gtk_icon_theme_get_search_path(icon_theme, &paths, &path_count);
+
+ gint i, j, out = 0;
+ gboolean found = FALSE;
+ for (i = 0; i < path_count; i++) {
+ gboolean keep = TRUE;
+ for (j = 0; emblem_paths_list[j] != NULL; j++) {
+ if (emblem_paths_list[j][0]) {
+ if (!g_strcmp0(paths[i], emblem_paths_list[j])) {
+ found = TRUE;
+ keep = FALSE;
+ g_free(paths[i]);
+ break;
+ }
+ }
+ }
+ if (keep) {
+ paths[out] = paths[i];
+ out++;
+ }
+ }
+
+ /* If we found one we need to reset the path to
+ accomodate the changes */
+ if (found) {
+ paths[out] = NULL; /* Clear the last one */
+ gtk_icon_theme_set_search_path(icon_theme, (const gchar **)paths, out);
+ }
+
+ g_strfreev(paths);
+exit:
+ g_hash_table_unref(emblem_paths_response);
+ return FALSE;
+}
+
+void get_emblem_paths_cb(GHashTable *emblem_paths_response, NautilusDropbox *cvs)
+{
+ if (!emblem_paths_response) {
+ emblem_paths_response = g_hash_table_new((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal);
+ g_hash_table_insert(emblem_paths_response, "path", DEFAULT_EMBLEM_PATHS);
+ } else {
+ /* Increase the ref so that finish_general_command doesn't delete it. */
+ g_hash_table_ref(emblem_paths_response);
+ }
+
+ g_mutex_lock(cvs->emblem_paths_mutex);
+ if (cvs->emblem_paths) {
+ g_idle_add((GSourceFunc) remove_emblem_paths, cvs->emblem_paths);
+ cvs->emblem_paths = NULL;
+ }
+ cvs->emblem_paths = emblem_paths_response;
+ g_mutex_unlock(cvs->emblem_paths_mutex);
+
+ g_idle_add((GSourceFunc) add_emblem_paths, g_hash_table_ref(emblem_paths_response));
+ g_idle_add((GSourceFunc) reset_all_files, cvs);
+}
+
+static void
+on_connect(NautilusDropbox *cvs) {
+ reset_all_files(cvs);
+
+ dropbox_command_client_send_command(&(cvs->dc.dcc),
+ (NautilusDropboxCommandResponseHandler) get_emblem_paths_cb,
+ cvs, "get_emblem_paths", NULL);
+}
+
+static void
+on_disconnect(NautilusDropbox *cvs) {
+ reset_all_files(cvs);
+
+ g_mutex_lock(cvs->emblem_paths_mutex);
+ /* This call will free the data too. */
+ g_idle_add((GSourceFunc) remove_emblem_paths, cvs->emblem_paths);
+ cvs->emblem_paths = NULL;
+ g_mutex_unlock(cvs->emblem_paths_mutex);
+}
+
+
+static void
+nautilus_dropbox_menu_provider_iface_init (NautilusMenuProviderIface *iface) {
+ iface->get_file_items = nautilus_dropbox_get_file_items;
+ return;
+}
+
+static void
+nautilus_dropbox_info_provider_iface_init (NautilusInfoProviderIface *iface) {
+ iface->update_file_info = nautilus_dropbox_update_file_info;
+ iface->cancel_update = nautilus_dropbox_cancel_update;
+ return;
+}
+
+static void
+nautilus_dropbox_instance_init (NautilusDropbox *cvs) {
+ cvs->filename2obj = g_hash_table_new_full((GHashFunc) g_str_hash,
+ (GEqualFunc) g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
+ cvs->obj2filename = g_hash_table_new_full((GHashFunc) g_direct_hash,
+ (GEqualFunc) g_direct_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) g_free);
+ cvs->emblem_paths_mutex = g_mutex_new();
+ cvs->emblem_paths = NULL;
+
+ /* setup the connection obj*/
+ dropbox_client_setup(&(cvs->dc));
+
+ /* our hooks */
+ nautilus_dropbox_hooks_add(&(cvs->dc.hookserv), "shell_touch",
+ (DropboxUpdateHook) handle_shell_touch, cvs);
+
+ /* add connection handlers */
+ dropbox_client_add_on_connect_hook(&(cvs->dc),
+ (DropboxClientConnectHook) on_connect,
+ cvs);
+ dropbox_client_add_on_disconnect_hook(&(cvs->dc),
+ (DropboxClientConnectHook) on_disconnect,
+ cvs);
+
+ /* now start the connection */
+ debug("about to start client connection");
+ dropbox_client_start(&(cvs->dc));
+
+ return;
+}
+
+static void
+nautilus_dropbox_class_init (NautilusDropboxClass *class) {
+}
+
+static void
+nautilus_dropbox_class_finalize (NautilusDropboxClass *class) {
+ debug("just checking");
+ /* kill threads here? */
+}
+
+GType
+nautilus_dropbox_get_type (void) {
+ return dropbox_type;
+}
+
+void
+nautilus_dropbox_register_type (GTypeModule *module) {
+ static const GTypeInfo info = {
+ sizeof (NautilusDropboxClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) nautilus_dropbox_class_init,
+ (GClassFinalizeFunc) nautilus_dropbox_class_finalize,
+ NULL,
+ sizeof (NautilusDropbox),
+ 0,
+ (GInstanceInitFunc) nautilus_dropbox_instance_init,
+ };
+
+ static const GInterfaceInfo menu_provider_iface_info = {
+ (GInterfaceInitFunc) nautilus_dropbox_menu_provider_iface_init,
+ NULL,
+ NULL
+ };
+
+ static const GInterfaceInfo info_provider_iface_info = {
+ (GInterfaceInitFunc) nautilus_dropbox_info_provider_iface_init,
+ NULL,
+ NULL
+ };
+
+ dropbox_type =
+ g_type_module_register_type(module,
+ G_TYPE_OBJECT,
+ "NautilusDropbox",
+ &info, 0);
+
+ g_type_module_add_interface (module,
+ dropbox_type,
+ NAUTILUS_TYPE_MENU_PROVIDER,
+ &menu_provider_iface_info);
+
+ g_type_module_add_interface (module,
+ dropbox_type,
+ NAUTILUS_TYPE_INFO_PROVIDER,
+ &info_provider_iface_info);
+}
diff --git a/src/nautilus-dropbox.h b/src/nautilus-dropbox.h
new file mode 100644
index 0000000..65734be
--- /dev/null
+++ b/src/nautilus-dropbox.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008 Evenflow, Inc.
+ *
+ * nautilus-dropbox.h
+ * Header file for nautilus-dropbox.c
+ *
+ * This file is part of nautilus-dropbox.
+ *
+ * nautilus-dropbox is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * nautilus-dropbox is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nautilus-dropbox. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NAUTILUS_DROPBOX_H
+#define NAUTILUS_DROPBOX_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libnautilus-extension/nautilus-info-provider.h>
+
+#include "dropbox-command-client.h"
+#include "nautilus-dropbox-hooks.h"
+#include "dropbox-client.h"
+
+G_BEGIN_DECLS
+
+/* Declarations for the dropbox extension object. This object will be
+ * instantiated by nautilus. It implements the GInterfaces
+ * exported by libnautilus. */
+
+#define NAUTILUS_TYPE_DROPBOX (nautilus_dropbox_get_type ())
+#define NAUTILUS_DROPBOX(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NAUTILUS_TYPE_DROPBOX, NautilusDropbox))
+#define NAUTILUS_IS_DROPBOX(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NAUTILUS_TYPE_DROPBOX))
+typedef struct _NautilusDropbox NautilusDropbox;
+typedef struct _NautilusDropboxClass NautilusDropboxClass;
+
+struct _NautilusDropbox {
+ GObject parent_slot;
+ GHashTable *filename2obj;
+ GHashTable *obj2filename;
+ GMutex *emblem_paths_mutex;
+ GHashTable *emblem_paths;
+ DropboxClient dc;
+};
+
+struct _NautilusDropboxClass {
+ GObjectClass parent_slot;
+};
+
+GType nautilus_dropbox_get_type(void);
+void nautilus_dropbox_register_type(GTypeModule *module);
+
+extern gboolean dropbox_use_nautilus_submenu_workaround;
+extern gboolean dropbox_use_operation_in_progress_workaround;
+
+G_END_DECLS
+
+#endif