<commit_before>
config  = require './config'
path    = require "path"
fs      = require "fs"
mkdirp  = require 'mkdirp'
log4js  = require 'log4js'
log     = log4js.getLogger("[#{config.name}]")

{exec}  = require 'child_process'
{spawn} = require "child_process"

# Utilities
{normalizeUserPath,
 safeForUser,
 escapePath,
 makedirp,
 slugify,
 chownr,
 encrypt,
 decrypt,
 getIds,
 KodingError,
 AuthorizationError} = require '../applications/utils.coffee'

# Dummy-Admins
# dummyAdmins = ["devrim", "sinan", "chris", "aleksey", "gokmen", "arvidkahl"]

startsWith = (str, part)-> str.trim().indexOf(part) is 0
endsWith   = (str, part)-> str.trim().indexOf(part, str.trim().length - part?.length) isnt -1

mounter    =

  mountDrive : (options, callback)->

    # mount already registered FTP/SSH remote to the users home directory

    # options
    #   remotetype : String # If its not provided we will try to guess from config
    #   remotehost : String # remote FTP/SFTP hostname
    #   remotepass : String # plain text password for ftp/ssh user.
    #   storepass  : Bool   # store password in config, default false

    # return
    #   callback error
    #   callback null, result (information message)

    {username, remotehost, remotepass, remotetype, remoteuser, storepass} = options

    @readMountInfo options, (err,res)=>
      if err?
        callback err
      else
        mounts = [mount for mount in res when (mount.remotehost is remotehost and mount.remoteuser is remoteuser)][0]

        if mounts.length is 0 or res.length is 0
          callback "No such remote registered with '#{remotehost}' name."
          return no

        if mounts.length > 1 and remotetype
          mounts = [mount for mount in mounts when mount.remotetype is remotetype][0]
          if mounts.length > 1
            callback "Duplicate entries for same remote, ask Koding admins for help."
            return no

        mount = mounts[0]

        mount.username   = username
        mount.storepass  = <PASSWORD>
        mount.mountonly  = yes

        if mount.remotepass?
          mount.remotepass = decrypt mount.remotepass, "#{config.encryptKey}==#{username}"
        else
          mount.remotepass = remotepass if remotepass

        switch mount.remotetype
          when "ftp"
            @mountFtpDrive mount, callback

  # Safe
  mountFtpDrive : (options, callback)->

    # mount FTP to the users home directory

    # options
    #   remoteuser : String # user on ftp server
    #   remotepass : String # plain text password for ftp user.
    #   remotehost : String # remote FTP hostname (FQDN)
    #   storepass  : Bool   # store password in config, default false

    # return
    #   callback error
    #   callback null, result (information message)

    options.remoteuser or= 'anonymous'
    options.remotepass or= 'anonymous'
    options.storepass  or= yes if options.remotepass is 'anonymous'
    options.remotetype   = 'ftp'

    {username, remoteuser, remotepass, remotehost, storepass, mountonly} = options

    unless remotehost
      callback "Remote host is not provided"
      return no

    options.mountpoint = escapePath path.join config.usersPath, username, config.baseMountDir, remoteuser
    options.mountpoint+= "@#{escapePath remotehost}"

    unless safeForUser username, options.mountpoint
      console.error "User [#{username}] is trying to make something bad: ", options.mountpoint
      callback "You are not authorized to do this."
      return no

    @getRemotesCount options, (count)=>
      if count >= config.maxAllowedRemotes
        callback "You've reached your limits for remote drives. Please remove one of remotes to add new one."
        return no

      # fetch user ID for curlftfs command
      getIds username, (err, ids)=>
        if err
          log.error error = "[ERROR] Can't find user ID: #{err}"
          callback error
        else
          @checkMountPoint options, (err, state)=>
            if state.mounted
              callback "Remote host is already mounted to #{state.mountpoint}"
            else
              {uid} = ids
              log.info "[OK] user ID for user #{username} is #{uid}"
              ftpfsopts = "#{config.ftpfs.opts},uid=#{uid},gid=#{uid},fsname=#{remotehost},user=#{remoteuser}:#{remotepass}"
              @createMountpoint options, (err)=>
                if err
                  callback err
                else
                  @spawnWrapper config.ftpfs.curlftpfs, ['-o', ftpfsopts, remotehost, options.mountpoint], (err)=>
                    if err
                      log.error error = "Couldn't mount remote FTP server #{remotehost}: #{err}"
                      fs.rmdir options.mountpoint, (err)->
                        log.error err if err
                        callback error
                    else
                      @remountVE options, (err)=>
                        if err
                          callback err
                        else
                          @updateMountCfg options, (err, res)->
                            callback null, res

  # Safe
  checkMountPoint : (options, callback)->
    #
    # this method checks if remount host mounted (it doesn't check for availability)
    #
    #

    #
    # return =
    #   mounted: Bool # true/false
    #   remotehost: String # remote FTP/SFTP hostname
    #   remoteuser: String # remote FTP/SFTP username
    #   mountpoint: Strint # full path to the mountpoint

    {username, remoteuser, remotehost, mountpoint} = options

    options.mountpoint = escapePath path.join config.usersPath, username, config.baseMountDir, remoteuser
    options.mountpoint+= "@#{escapePath remotehost}"

    unless safeForUser username, options.mountpoint
      console.error "User [#{username}] is trying to make something bad: ", options.mountpoint
      callback "You are not authorized to do this."
      return no

    res = {mounted : false, remotehost, mountpoint : options.mountpoint}

    rs = fs.createReadStream '/proc/mounts', flags: 'r'
    rs.setEncoding()

    rs.on 'error', (err)->
      console.error error = "Unexpected error : couldn't retrieve mount info: #{err.message}"
      callback error

    rs.on 'data', (data)->
      mounts = [mount.split(' ', 2) for mount in data.split('\n') when startsWith mount, remotehost][0]
      if mounts.length > 0<commit_msg> Wait until end event fired<commit_after>
config  = require './config'
path    = require "path"
fs      = require "fs"
mkdirp  = require 'mkdirp'
log4js  = require 'log4js'
log     = log4js.getLogger("[#{config.name}]")

{exec}  = require 'child_process'
{spawn} = require "child_process"

# Utilities
{normalizeUserPath,
 safeForUser,
 escapePath,
 makedirp,
 slugify,
 chownr,
 encrypt,
 decrypt,
 getIds,
 KodingError,
 AuthorizationError} = require '../applications/utils.coffee'

# Dummy-Admins
# dummyAdmins = ["devrim", "sinan", "chris", "aleksey", "gokmen", "arvidkahl"]

startsWith = (str, part)-> str.trim().indexOf(part) is 0
endsWith   = (str, part)-> str.trim().indexOf(part, str.trim().length - part?.length) isnt -1

mounter    =

  mountDrive : (options, callback)->

    # mount already registered FTP/SSH remote to the users home directory

    # options
    #   remotetype : String # If its not provided we will try to guess from config
    #   remotehost : String # remote FTP/SFTP hostname
    #   remotepass : String # plain text password for ftp/ssh user.
    #   storepass  : Bool   # store password in config, default false

    # return
    #   callback error
    #   callback null, result (information message)

    {username, remotehost, remotepass, remotetype, remoteuser, storepass} = options

    @readMountInfo options, (err,res)=>
      if err?
        callback err
      else
        mounts = [mount for mount in res when (mount.remotehost is remotehost and mount.remoteuser is remoteuser)][0]

        if mounts.length is 0 or res.length is 0
          callback "No such remote registered with '#{remotehost}' name."
          return no

        if mounts.length > 1 and remotetype
          mounts = [mount for mount in mounts when mount.remotetype is remotetype][0]
          if mounts.length > 1
            callback "Duplicate entries for same remote, ask Koding admins for help."
            return no

        mount = mounts[0]

        mount.username   = username
        mount.storepass  = <PASSWORD>
        mount.mountonly  = yes

        if mount.remotepass?
          mount.remotepass = decrypt mount.remotepass, "#{config.encryptKey}==#{username}"
        else
          mount.remotepass = remotepass if remotepass

        switch mount.remotetype
          when "ftp"
            @mountFtpDrive mount, callback

  # Safe
  mountFtpDrive : (options, callback)->

    # mount FTP to the users home directory

    # options
    #   remoteuser : String # user on ftp server
    #   remotepass : String # plain text password for ftp user.
    #   remotehost : String # remote FTP hostname (FQDN)
    #   storepass  : Bool   # store password in config, default false

    # return
    #   callback error
    #   callback null, result (information message)

    options.remoteuser or= 'anonymous'
    options.remotepass or= 'anonymous'
    options.storepass  or= yes if options.remotepass is 'anonymous'
    options.remotetype   = 'ftp'

    {username, remoteuser, remotepass, remotehost, storepass, mountonly} = options

    unless remotehost
      callback "Remote host is not provided"
      return no

    options.mountpoint = escapePath path.join config.usersPath, username, config.baseMountDir, remoteuser
    options.mountpoint+= "@#{escapePath remotehost}"

    unless safeForUser username, options.mountpoint
      console.error "User [#{username}] is trying to make something bad: ", options.mountpoint
      callback "You are not authorized to do this."
      return no

    @getRemotesCount options, (count)=>
      if count >= config.maxAllowedRemotes
        callback "You've reached your limits for remote drives. Please remove one of remotes to add new one."
        return no

      # fetch user ID for curlftfs command
      getIds username, (err, ids)=>
        if err
          log.error error = "[ERROR] Can't find user ID: #{err}"
          callback error
        else
          @checkMountPoint options, (err, state)=>
            if state.mounted
              callback "Remote host is already mounted to #{state.mountpoint}"
            else
              {uid} = ids
              log.info "[OK] user ID for user #{username} is #{uid}"
              ftpfsopts = "#{config.ftpfs.opts},uid=#{uid},gid=#{uid},fsname=#{remotehost},user=#{remoteuser}:#{remotepass}"
              @createMountpoint options, (err)=>
                if err
                  callback err
                else
                  @spawnWrapper config.ftpfs.curlftpfs, ['-o', ftpfsopts, remotehost, options.mountpoint], (err)=>
                    if err
                      log.error error = "Couldn't mount remote FTP server #{remotehost}: #{err}"
                      fs.rmdir options.mountpoint, (err)->
                        log.error err if err
                        callback error
                    else
                      @remountVE options, (err)=>
                        if err
                          callback err
                        else
                          @updateMountCfg options, (err, res)->
                            callback null, res

  # Safe
  checkMountPoint : (options, callback)->
    #
    # this method checks if remount host mounted (it doesn't check for availability)
    #
    #

    #
    # return =
    #   mounted: Bool # true/false
    #   remotehost: String # remote FTP/SFTP hostname
    #   remoteuser: String # remote FTP/SFTP username
    #   mountpoint: Strint # full path to the mountpoint

    {username, remoteuser, remotehost, mountpoint} = options

    options.mountpoint = escapePath path.join config.usersPath, username, config.baseMountDir, remoteuser
    options.mountpoint+= "@#{escapePath remotehost}"

    unless safeForUser username, options.mountpoint
      console.error "User [#{username}] is trying to make something bad: ", options.mountpoint
      callback "You are not authorized to do this."
      return no

    fc  = ''
    res = {mounted : false, remotehost, mountpoint : options.mountpoint}

    rs = fs.createReadStream '/proc/mounts', flags: 'r'
    rs.setEncoding()

    rs.on 'error', (err)->
      console.error error = "Unexpected error : couldn't retrieve mount info: #{err.message}"
      callback error

    rs.on 'data', (data)->
      fc += data

    rs.on 'end', ->
      mounts = [mount.split(' ', 2) for mount in fc.split('\n') when startsWith mount, remotehost][0]
      if mounts.length > 0
{'fraction_non_alphanumeric': 0.09686987744906721, 'fraction_numerical': 0.002341737569276403, 'mean_word_length': 2.3217526575058334, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1192329', 'n_tokens_mistral': 3689, 'n_tokens_neox': 3531, 'n_words': 1171}