<commit_before>'use babel';

import FS from 'fs-plus';
import Path from 'path';
import SSH2 from 'ssh2';
import Connector from '../connector';
import { traverseTree } from '../helpers';

class ConnectorSFTP extends Connector {
  constructor(...args) {
    super(...args);

    this.ssh2 = null;
    this.sftp = null;
    this.status = 'disconnected';
  }

  isConnected() {
    const self = this;

    return self.status !== 'disconnected' && self.sftp;
  }

  connect(info, completed) {
    const self = this;

    self.info = info;
    self.info.debug = true;
    self.customFilePermissions = self.info.filePermissions;

    const debug = self.info.debug;
    const connectInfo = Object.assign({}, self.info);

    delete connectInfo.filePermissions;

    self.status = 'connecting';

    self.ssh2 = new SSH2();

    self.ssh2.on('banner', (msg) => {
      self.emit('greeting', msg);
    });

    self.ssh2.on('ready', () => {
      self.ssh2.sftp((err, sftp) => {
        if (err) {
          self.disconnect();
          return;
        }

        if (self.info.remoteShell) {
          self.emit('openingShell', self.info.remoteShell);

          self.ssh2.shell((shellErr, stream) => {
            if (shellErr) {
              self.emit('error', shellErr);
              self.disconnect();
              return;
            }

            stream.end(`${self.info.remoteShell}\nexit\n`);
          });
        }

        if (self.info.remoteCommand) {
          self.emit('executingCommand', self.info.remoteCommand);

          self.ssh2.exec(self.info.remoteCommand, (remoteErr) => {
            if (remoteErr) {
              self.emit('error', remoteErr);
              self.disconnect();
            }
          });
        }

        self.status = 'connected';

        self.sftp = sftp;
        self.sftp.on('end', () => {
          self.disconnect();
          self.emit('ended');
        });

        self.emit('connected');

        if (typeof completed === 'function') {
          completed.apply(self, []);
        }
      });
    });

    self.ssh2.on('end', () => {
      self.disconnect();
      self.emit('ended');
    });

    self.ssh2.on('close', () => {
      self.disconnect();
      self.emit('closed');
    });

    self.ssh2.on('error', (err) => {
      self.emit('error', err);
    });

    self.ssh2.on('debug', (str) => {
      if (typeof debug === 'function') {
        debug(...[str]);
      }
    });

    self.ssh2.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => {
      finish([self.info.password]);
    });

    try {
      self.ssh2.connect(connectInfo);
    } catch (err) {
      atom.notifications.addError('SFTP connection attempt failed', {
        detail: err,
        dismissable: true,
      });
    }
<commit_msg>Add more notification #962<commit_after>'use babel';

import FS from 'fs-plus';
import Path from 'path';
import SSH2 from 'ssh2';
import Connector from '../connector';
import { traverseTree } from '../helpers';

class ConnectorSFTP extends Connector {
  constructor(...args) {
    super(...args);

    this.ssh2 = null;
    this.sftp = null;
    this.status = 'disconnected';
  }

  isConnected() {
    const self = this;

    return self.status !== 'disconnected' && self.sftp;
  }

  connect(info, completed) {
    const self = this;

    self.info = info;
    self.info.debug = true;
    self.customFilePermissions = self.info.filePermissions;

    const debug = self.info.debug;
    const connectInfo = Object.assign({}, self.info);

    delete connectInfo.filePermissions;

    self.status = 'connecting';

    self.ssh2 = new SSH2();

    self.ssh2.on('banner', (msg) => {
      self.emit('greeting', msg);
    });

    self.ssh2.on('ready', () => {
      self.ssh2.sftp((err, sftp) => {
        if (err) {
          self.disconnect();
          return;
        }

        if (self.info.remoteShell) {
          self.emit('openingShell', self.info.remoteShell);

          self.ssh2.shell((shellErr, stream) => {
            if (shellErr) {
              self.emit('error', shellErr);
              self.disconnect();
              return;
            }

            stream.end(`${self.info.remoteShell}\nexit\n`);
          });
        }

        if (self.info.remoteCommand) {
          self.emit('executingCommand', self.info.remoteCommand);

          self.ssh2.exec(self.info.remoteCommand, (remoteErr) => {
            if (remoteErr) {
              self.emit('error', remoteErr);
              self.disconnect();
            }
          });
        }

        self.status = 'connected';

        self.sftp = sftp;
        self.sftp.on('end', () => {
          self.disconnect();
          self.emit('ended');
        });

        self.emit('connected');

        if (typeof completed === 'function') {
          completed.apply(self, []);
        }
      });
    });

    self.ssh2.on('end', () => {
      self.disconnect();
      self.emit('ended');
    });

    self.ssh2.on('close', () => {
      self.disconnect();
      self.emit('closed');
    });

    self.ssh2.on('error', (err) => {
      self.emit('error', err);
    });

    self.ssh2.on('debug', (str) => {
      if (typeof debug === 'function') {
        debug(...[str]);
      }
    });

    self.ssh2.on('keyboard-interactive', (name, instructions, instructionsLang, prompts, finish) => {
      if (typeof self.info.password !== 'undefined') {
        finish([self.info.password]);
      } else {
        atom.notifications.addInfo('Keyboard Interactive is on, but the password is not defined.', {
          description: 'Try turning on <b>"promptForPass": true</b>',
        });
      }
    });

    try {
      self.ssh2.connect(connectInfo);
    } catch (err) {
      atom.notifications.addError('SFTP connection attempt failed', {
        detail: err,
        dismissable: true,
      });
    }

{'fraction_non_alphanumeric': 0.16808438244300783, 'fraction_numerical': 0.005954406260632868, 'mean_word_length': 1.9632056451612903, 'pattern_counts': {'":': 1, '<': 5, '<?xml version=': 0, '>': 27, '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': '1320863', 'n_tokens_mistral': 1881, 'n_tokens_neox': 1789, 'n_words': 326}