diff options
-rw-r--r-- | source3/Makefile.in | 29 | ||||
-rw-r--r-- | source3/configure.in | 3 | ||||
-rw-r--r-- | source3/include/localedir.h | 6 | ||||
-rwxr-xr-x | source3/locale/pam_winbind/genmsg | 25 | ||||
-rw-r--r-- | source3/localedir.c | 3 | ||||
-rw-r--r-- | source3/m4/check_path.m4 | 19 | ||||
-rw-r--r-- | source3/nsswitch/pam_winbind.c | 117 | ||||
-rw-r--r-- | source3/nsswitch/pam_winbind.h | 15 | ||||
-rw-r--r-- | source3/script/installmo.sh | 83 | ||||
-rw-r--r-- | source3/script/uninstallmo.sh | 1 |
10 files changed, 244 insertions, 57 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 6e40ba404a..4a0590c8ed 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -140,6 +140,9 @@ PRIVATE_DIR = $(PRIVATEDIR) # This is where SWAT images and help files go SWATDIR = @swatdir@ +# This is where locale(mo) files go +LOCALEDIR= @localedir@ + # the directory where lock files go LOCKDIR = @lockdir@ @@ -173,7 +176,8 @@ PATH_FLAGS = -DSMB_PASSWD_FILE=\"$(SMB_PASSWD_FILE)\" \ -DCONFIGDIR=\"$(CONFIGDIR)\" \ -DCODEPAGEDIR=\"$(CODEPAGEDIR)\" \ -DCACHEDIR=\"$(CACHEDIR)\" \ - -DSTATEDIR=\"$(STATEDIR)\" + -DSTATEDIR=\"$(STATEDIR)\" \ + -DLOCALEDIR=\"$(LOCALEDIR)\" # Note that all executable programs now provide for an optional executable suffix. @@ -803,7 +807,7 @@ RPCCLIENT_OBJ = $(RPCCLIENT_OBJ1) \ $(LIBADS_OBJ) $(POPT_LIB_OBJ) \ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) $(LDB_OBJ) -PAM_WINBIND_OBJ = nsswitch/pam_winbind.o $(WBCOMMON_OBJ) \ +PAM_WINBIND_OBJ = nsswitch/pam_winbind.o localedir.o $(WBCOMMON_OBJ) \ $(LIBREPLACE_OBJ) @BUILD_INIPARSER@ LIBSMBCLIENT_OBJ0 = \ @@ -1312,6 +1316,13 @@ dynconfig.o: dynconfig.c Makefile echo "$(COMPILE_CC_PATH)" 1>&2;\ $(COMPILE_CC_PATH) >/dev/null 2>&1 +localedir.o: localedir.c Makefile + @echo Compiling $*.c + @$(COMPILE_CC_PATH) && exit 0;\ + echo "The following command failed:" 1>&2;\ + echo "$(COMPILE_CC_PATH)" 1>&2;\ + $(COMPILE_CC_PATH) >/dev/null 2>&1 + lib/pidfile.o: lib/pidfile.c @echo Compiling $*.c @$(COMPILE_CC_PATH) && exit 0;\ @@ -2558,7 +2569,7 @@ bin/test_lp_load@EXEEXT@: $(BINARY_PREREQS) $(TEST_LP_LOAD_OBJ) @BUILD_POPT@ @LI install:: installservers installbin @INSTALL_CIFSMOUNT@ @INSTALL_CIFSUPCALL@ installman \ installscripts installdat installmodules @SWAT_INSTALL_TARGETS@ \ - @INSTALL_PAM_MODULES@ installlibs + @INSTALL_PAM_MODULES@ installlibs installmo install-everything:: install installmodules @@ -2571,7 +2582,7 @@ install-everything:: install installmodules # is not used installdirs:: - @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(BINDIR) $(SBINDIR) $(LIBDIR) $(VARDIR) $(PRIVATEDIR) $(PIDDIR) $(LOCKDIR) $(MANDIR) $(CODEPAGEDIR) $(MODULESDIR) + @$(SHELL) $(srcdir)/script/installdirs.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(BINDIR) $(SBINDIR) $(LIBDIR) $(VARDIR) $(PRIVATEDIR) $(PIDDIR) $(LOCKDIR) $(MANDIR) $(CODEPAGEDIR) $(MODULESDIR) $(LOCALEDIR) installservers:: all installdirs @$(SHELL) script/installbin.sh $(INSTALLPERMS_BIN) $(DESTDIR) $(prefix) $(SBINDIR) $(SBIN_PROGS) @@ -2637,6 +2648,9 @@ revert:: installman:: installdirs @$(SHELL) $(srcdir)/script/installman.sh $(DESTDIR)$(MANDIR) $(srcdir) C "@ROFF@" +installmo:: all installdirs + @$(SHELL) $(srcdir)/script/installmo.sh $(DESTDIR) $(LOCALEDIR) $(srcdir) + .PHONY: showlayout showlayout:: @@ -2656,7 +2670,10 @@ showlayout:: @echo " codepagedir: $(CODEPAGEDIR)" -uninstall:: uninstallman uninstallservers uninstallbin @UNINSTALL_CIFSMOUNT@ @UNINSTALL_CIFSUPCALL@ uninstallscripts uninstalldat uninstallswat uninstallmodules uninstalllibs @UNINSTALL_PAM_MODULES@ +uninstall:: uninstallmo uninstallman uninstallservers uninstallbin @UNINSTALL_CIFSMOUNT@ @UNINSTALL_CIFSUPCALL@ uninstallscripts uninstalldat uninstallswat uninstallmodules uninstalllibs @UNINSTALL_PAM_MODULES@ + +uninstallmo:: + @$(SHELL) $(srcdir)/script/uninstallmo.sh $(DESTDIR) $(LOCALEDIR) $(srcdir) uninstallman:: @$(SHELL) $(srcdir)/script/uninstallman.sh $(DESTDIR)$(MANDIR) $(srcdir) C @@ -2701,7 +2718,7 @@ uninstallpammodules:: done # Toplevel clean files -TOPFILES=dynconfig.o +TOPFILES=dynconfig.o localedir.o cleanlibs:: -rm -f ../lib/*/*.o ../lib/*/*/*.o \ diff --git a/source3/configure.in b/source3/configure.in index 24341e0bec..1adb56ad91 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -654,7 +654,7 @@ AUTH_LIBS="${AUTH_LIBS} ${CRYPT_LIBS}" AC_CHECK_HEADERS(aio.h sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h rpc/nettype.h) AC_CHECK_HEADERS(unistd.h grp.h sys/id.h memory.h alloca.h) -AC_CHECK_HEADERS(limits.h float.h pthread.h) +AC_CHECK_HEADERS(limits.h float.h pthread.h libintl.h) AC_CHECK_HEADERS(rpc/rpc.h rpcsvc/nis.h rpcsvc/ypclnt.h) AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/ipc.h sys/prctl.h) AC_CHECK_HEADERS(sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h) @@ -1029,6 +1029,7 @@ AC_CHECK_FUNCS(memalign posix_memalign hstrerror) AC_CHECK_HEADERS(sys/mman.h) # setbuffer, shmget, shm_open are needed for smbtorture AC_CHECK_FUNCS(shmget shm_open) +AC_CHECK_FUNCS(gettext dgettext) # Find a method of generating a stack trace AC_CHECK_HEADERS(execinfo.h libexc.h libunwind.h) diff --git a/source3/include/localedir.h b/source3/include/localedir.h new file mode 100644 index 0000000000..2a291d3ceb --- /dev/null +++ b/source3/include/localedir.h @@ -0,0 +1,6 @@ +#ifndef __LOCALEDIR_H__ +#define __LOCALEDIR_H__ + +extern const char *dyn_LOCALEDIR; + +#endif diff --git a/source3/locale/pam_winbind/genmsg b/source3/locale/pam_winbind/genmsg new file mode 100755 index 0000000000..5aa258aa85 --- /dev/null +++ b/source3/locale/pam_winbind/genmsg @@ -0,0 +1,25 @@ +#!/bin/sh + +FILES="../../nsswitch/pam_winbind.c ../../nsswitch/pam_winbind.h" +LANGS="af ar bg bn bs ca cs cy da de el en_GB en_US es et fi fr gl gu he hi hr hu id it ja ka km ko lo lt mk mr nb nl pa pl pt_BR pt ro ru si sk sl sr sv ta th tr uk vi wa xh zh_CN zh_TW zu" + +XGETTEXT=xgettext +MSGMERGE=msgmerge + +WIDTH=256 + +$XGETTEXT --default-domain="pam_winbind" \ + --add-comments \ + --keyword=_ --keyword=N_ \ + --width=${WIDTH} \ + ${FILES} + +for lang in ${LANGS}; do + echo -n $lang + touch ${lang}.po + mv ${lang}.po ${lang}.po.old + ${MSGMERGE} --width=${WIDTH} ${lang}.po.old pam_winbind.po -o ${lang}.po + rm -fr ${lang}.po.old +done + +rm -fr pam_winbind.po diff --git a/source3/localedir.c b/source3/localedir.c new file mode 100644 index 0000000000..20f69219ed --- /dev/null +++ b/source3/localedir.c @@ -0,0 +1,3 @@ +#include "localedir.h" + +const char *dyn_LOCALEDIR = LOCALEDIR; diff --git a/source3/m4/check_path.m4 b/source3/m4/check_path.m4 index 0cff397c93..da6c922233 100644 --- a/source3/m4/check_path.m4 +++ b/source3/m4/check_path.m4 @@ -30,6 +30,7 @@ swatdir="\${prefix}/swat" codepagedir="\${MODULESDIR}" statedir="\${LOCKDIR}" cachedir="\${LOCKDIR}" +localedir="\${prefix}/share/locale" AC_ARG_WITH(fhs, [AS_HELP_STRING([--with-fhs],[Use FHS-compliant paths (default=no)])], @@ -242,6 +243,23 @@ AC_ARG_WITH(mandir, ;; esac]) +################################################ +# set locale directory location +AC_ARG_WITH(localedir, +[ --with-localedir=DIR Where to put po files ($ac_default_prefix/share/locale)], +[ case "$withval" in + yes|no) + # + # Just in case anybody does it + # + AC_MSG_WARN([--with-localedir called without argument - will use default]) + ;; + *) + localedir="$withval" + ;; + esac]) + + AC_SUBST(configdir) AC_SUBST(lockdir) AC_SUBST(piddir) @@ -258,6 +276,7 @@ AC_SUBST(cachedir) AC_SUBST(rootsbindir) AC_SUBST(pammodulesdir) AC_SUBST(modulesdir) +AC_SUBST(localedir) ################################################# # set prefix for 'make test' diff --git a/source3/nsswitch/pam_winbind.c b/source3/nsswitch/pam_winbind.c index 0c861e9f97..2c46a0c839 100644 --- a/source3/nsswitch/pam_winbind.c +++ b/source3/nsswitch/pam_winbind.c @@ -147,6 +147,21 @@ static const char *_pam_error_code_str(int err) #define MAX_PASSWD_TRIES 3 +#ifdef HAVE_GETTEXT +static char initialized = 0; + +static inline void textdomain_init(void); +static inline void textdomain_init(void) +{ + if (!initialized) { + bindtextdomain(MODULE_NAME, dyn_LOCALEDIR); + initialized = 1; + } + return; +} +#endif + + /* * Work around the pam API that has functions with void ** as parameters * These lead to strict aliasing warnings with gcc. @@ -515,6 +530,10 @@ static int _pam_winbind_init_context(pam_handle_t *pamh, { struct pwb_context *r = NULL; +#ifdef HAVE_GETTEXT + textdomain_init(); +#endif + r = TALLOC_ZERO_P(NULL, struct pwb_context); if (!r) { return PAM_BUF_ERR; @@ -557,44 +576,44 @@ static const struct ntstatus_errors { const char *error_string; } ntstatus_errors[] = { {"NT_STATUS_OK", - "Success"}, + N_("Success")}, {"NT_STATUS_BACKUP_CONTROLLER", - "No primary Domain Controler available"}, + N_("No primary Domain Controler available")}, {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", - "No domain controllers found"}, + N_("No domain controllers found")}, {"NT_STATUS_NO_LOGON_SERVERS", - "No logon servers"}, + N_("No logon servers")}, {"NT_STATUS_PWD_TOO_SHORT", - "Password too short"}, + N_("Password too short")}, {"NT_STATUS_PWD_TOO_RECENT", - "The password of this user is too recent to change"}, + N_("The password of this user is too recent to change")}, {"NT_STATUS_PWD_HISTORY_CONFLICT", - "Password is already in password history"}, + N_("Password is already in password history")}, {"NT_STATUS_PASSWORD_EXPIRED", - "Your password has expired"}, + N_("Your password has expired")}, {"NT_STATUS_PASSWORD_MUST_CHANGE", - "You need to change your password now"}, + N_("You need to change your password now")}, {"NT_STATUS_INVALID_WORKSTATION", - "You are not allowed to logon from this workstation"}, + N_("You are not allowed to logon from this workstation")}, {"NT_STATUS_INVALID_LOGON_HOURS", - "You are not allowed to logon at this time"}, + N_("You are not allowed to logon at this time")}, {"NT_STATUS_ACCOUNT_EXPIRED", "Your account has expired. " - "Please contact your System administrator"}, /* SCNR */ + N_("Please contact your System administrator")}, /* SCNR */ {"NT_STATUS_ACCOUNT_DISABLED", "Your account is disabled. " - "Please contact your System administrator"}, /* SCNR */ + N_("Please contact your System administrator")}, /* SCNR */ {"NT_STATUS_ACCOUNT_LOCKED_OUT", "Your account has been locked. " - "Please contact your System administrator"}, /* SCNR */ + N_("Please contact your System administrator")}, /* SCNR */ {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", - "Invalid Trust Account"}, + N_("Invalid Trust Account")}, {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", - "Invalid Trust Account"}, + N_("Invalid Trust Account")}, {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", - "Invalid Trust Account"}, + N_("Invalid Trust Account")}, {"NT_STATUS_ACCESS_DENIED", - "Access is denied"}, + N_("Access is denied")}, {NULL, NULL} }; @@ -604,7 +623,7 @@ static const char *_get_ntstatus_error_string(const char *nt_status_string) for (i=0; ntstatus_errors[i].ntstatus_string != NULL; i++) { if (!strcasecmp(ntstatus_errors[i].ntstatus_string, nt_status_string)) { - return ntstatus_errors[i].error_string; + return _(ntstatus_errors[i].error_string); } } return NULL; @@ -832,14 +851,14 @@ static bool _pam_send_password_expiry_message(struct pwb_context *ctx, if (days == 0) { _make_remark(ctx, PAM_TEXT_INFO, - "Your password expires today"); + _("Your password expires today")); return true; } if (days > 0 && days < warn_pwd_expire) { _make_remark_format(ctx, PAM_TEXT_INFO, - "Your password will expire in %d %s", - days, (days > 1) ? "days":"day"); + _("Your password will expire in %d %s"), + days, (days > 1) ? _("days"):_("day")); return true; } @@ -1231,9 +1250,9 @@ static void _pam_warn_logon_type(struct pwb_context *ctx, if (PAM_WB_GRACE_LOGON(info3_user_flgs)) { _make_remark(ctx, PAM_ERROR_MSG, - "Grace login. " - "Please change your password as soon you're " - "online again"); + _("Grace login. " + "Please change your password as soon you're " + "online again")); _pam_log_debug(ctx, LOG_DEBUG, "User %s logged on using grace logon\n", username); @@ -1241,9 +1260,9 @@ static void _pam_warn_logon_type(struct pwb_context *ctx, } else if (PAM_WB_CACHED_LOGON(info3_user_flgs)) { _make_remark(ctx, PAM_ERROR_MSG, - "Domain Controller unreachable, " - "using cached credentials instead. " - "Network resources may be unavailable"); + _("Domain Controller unreachable, " + "using cached credentials instead. " + "Network resources may be unavailable")); _pam_log_debug(ctx, LOG_DEBUG, "User %s logged on using cached credentials\n", username); @@ -1266,10 +1285,10 @@ static void _pam_warn_krb5_failure(struct pwb_context *ctx, { if (PAM_WB_KRB5_CLOCK_SKEW(info3_user_flgs)) { _make_remark(ctx, PAM_ERROR_MSG, - "Failed to establish your Kerberos Ticket cache " - "due time differences\n" - "with the domain controller. " - "Please verify the system time.\n"); + _("Failed to establish your Kerberos Ticket cache " + "due time differences\n" + "with the domain controller. " + "Please verify the system time.\n")); _pam_log_debug(ctx, LOG_DEBUG, "User %s: Clock skew when getting Krb5 TGT\n", username); @@ -1334,7 +1353,7 @@ static char *_pam_compose_pwd_restriction_string(struct pwb_context *ctx, goto failed; } - str = talloc_asprintf(ctx, "Your password "); + str = talloc_asprintf(ctx, _("Your password ")); if (!str) { goto failed; } @@ -1350,8 +1369,8 @@ static char *_pam_compose_pwd_restriction_string(struct pwb_context *ctx, if (i->password_history > 0) { str = talloc_asprintf_append(str, - "cannot repeat any of your previous %d " - "passwords; ", + _("cannot repeat any of your previous %d " + "passwords; "), i->password_history); if (!str) { goto failed; @@ -1360,19 +1379,19 @@ static char *_pam_compose_pwd_restriction_string(struct pwb_context *ctx, if (i->password_properties & WBC_DOMAIN_PASSWORD_COMPLEX) { str = talloc_asprintf_append(str, - "must contain capitals, numerals " - "or punctuation; " - "and cannot contain your account " - "or full name; "); + _("must contain capitals, numerals " + "or punctuation; " + "and cannot contain your account " + "or full name; ")); if (!str) { goto failed; } } str = talloc_asprintf_append(str, - "Please type a different password. " - "Type a password which meets these requirements in " - "both text boxes."); + _("Please type a different password. " + "Type a password which meets these requirements in " + "both text boxes.")); if (!str) { goto failed; } @@ -1855,8 +1874,8 @@ static int winbind_chauthtok_request(struct pwb_context *ctx, break; case WBC_PWD_CHANGE_REJECT_COMPLEXITY: _make_remark(ctx, PAM_ERROR_MSG, - "Password does not meet " - "complexity requirements"); + _("Password does not meet " + "complexity requirements")); break; default: _pam_log_debug(ctx, LOG_DEBUG, @@ -2489,7 +2508,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags, } retval = _winbind_read_password(ctx, ctx->ctrl, NULL, - "Password: ", NULL, + _("Password: "), NULL, &password); if (retval != PAM_SUCCESS) { @@ -2897,7 +2916,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, /* instruct user what is happening */ -#define greeting "Changing password for" +#define greeting _("Changing password for") Announce = talloc_asprintf(ctx, "%s %s", greeting, user); if (!Announce) { _pam_log(ctx, LOG_CRIT, @@ -2910,7 +2929,7 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, lctrl = ctx->ctrl | WINBIND__OLD_PASSWORD; ret = _winbind_read_password(ctx, lctrl, Announce, - "(current) NT password: ", + _("(current) NT password: "), NULL, (const char **) &pass_old); TALLOC_FREE(Announce); @@ -2980,8 +2999,8 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, ret = _winbind_read_password(ctx, lctrl, NULL, - "Enter new NT password: ", - "Retype new NT password: ", + _("Enter new NT password: "), + _("Retype new NT password: "), (const char **)&pass_new); if (ret != PAM_SUCCESS) { diff --git a/source3/nsswitch/pam_winbind.h b/source3/nsswitch/pam_winbind.h index cb6f450ccb..0656f5972e 100644 --- a/source3/nsswitch/pam_winbind.h +++ b/source3/nsswitch/pam_winbind.h @@ -9,6 +9,7 @@ #include "system/time.h" #include <talloc.h> #include "libwbclient/wbclient.h" +#include "localedir.h" #define MODULE_NAME "pam_winbind" #define PAM_SM_AUTH @@ -22,6 +23,10 @@ #include <iniparser.h> +#ifdef HAVE_LIBINTL_H +#include <libintl.h> +#endif + #ifndef LINUX /* Solaris always uses dynamic pam modules */ @@ -101,12 +106,20 @@ do { \ #define WINBIND_WARN_PWD_EXPIRE 0x00002000 #define WINBIND_MKHOMEDIR 0x00004000 +#if defined(HAVE_GETTEXT) && !defined(__LCLINT__) +#define _(string) dgettext(MODULE_NAME, string) +#else +#define _(string) string +#endif + +#define N_(string) string + /* * here is the string to inform the user that the new passwords they * typed were not the same. */ -#define MISTYPED_PASS "Sorry, passwords do not match" +#define MISTYPED_PASS _("Sorry, passwords do not match") #define on(x, y) (x & y) #define off(x, y) (!(x & y)) diff --git a/source3/script/installmo.sh b/source3/script/installmo.sh new file mode 100644 index 0000000000..a1f9c58e27 --- /dev/null +++ b/source3/script/installmo.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +DESTDIR=$1 +LOCALEDIR=`echo $2 | sed 's/\/\//\//g'` +SRCDIR=$3/ +MSGFMT=msgfmt + +case $0 in + *uninstall*) + if test ! -d "$DESTDIR/$LOCALEDIR"; then + echo "Directory $DESTDIR/$LOCALEDIR doesn't exist!" + echo "Do a \"make installmo\" or \"make install\" first." + exit 1 + fi + mode='uninstall' + ;; + *) + mode='install' + ;; +esac + +for dir in $SRCDIR/locale/*; do + MODULE=`basename $dir` + for f in $SRCDIR/locale/$MODULE/*.po; do + BASE=`basename $f` + LANGUAGE=`echo $BASE | sed 's/\.po//g'` + FNAME="$DESTDIR/$LOCALEDIR/$LANGUAGE/LC_MESSAGES/$MODULE.mo" + if test ! -d "$DESTDIR/$LOCALEDIR/$LANGUAGE/LC_MESSAGES/"; then + mkdir -p "$DESTDIR/$LOCALEDIR/$LANGUAGE/LC_MESSAGES/" + fi + if test "$mode" = 'install'; then + echo "Installing $f as $FNAME" + touch "$FNAME" + $MSGFMT "$f" -f -o "$FNAME" + if test ! -f "$FNAME"; then + echo "Cannot install $FNAME. Does $USER have privileges?" + exit 1 + fi + chmod 0644 "$FNAME" + elif test "$mode" = 'uninstall'; then + echo "removing $FNAME" + rm -f "$FNAME" + if test -f "$FNAME"; then + echo "Cannot remove $FNAME. Does $USER have privileges?" + exit 1 + fi + else + echo "Unknown mode $mode. script called as $0." + exit 1 + fi + done + if test "$mode" = 'install'; then + cat << EOF +============================================================== +MO files for $MODULE are installed. +============================================================== +EOF + else + cat << EOF +============================================================== +MO files for $MODULE are removed. +============================================================== +EOF + fi +done + +if test "$mode" = 'install'; then + cat << EOF +============================================================== +All MO files for Samba are installed. You can use "make uninstall" +or "make uninstallmo" to remove them. +============================================================== +EOF +else + cat << EOF +============================================================== +All MO files for Samba are removed. you can use "make install" +or "make installmo" to install them. +============================================================== +EOF +fi + +exit 0 diff --git a/source3/script/uninstallmo.sh b/source3/script/uninstallmo.sh new file mode 100644 index 0000000000..5b4475f5c2 --- /dev/null +++ b/source3/script/uninstallmo.sh @@ -0,0 +1 @@ +installmo.sh |