├── .babelrc
├── .electron-vue
├── build.js
├── dev-client.js
├── dev-runner.js
├── revision.js
├── webpack.main.config.js
├── webpack.renderer.config.js
└── webpack.web.config.js
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .imapsync
└── upgrade.js
├── .travis.yml
├── LICENSE
├── README.md
├── _config.yml
├── appveyor.yml
├── build
└── icons
│ ├── 256x256.png
│ ├── icon.icns
│ └── icon.ico
├── dist
├── electron
│ └── .gitkeep
└── web
│ └── .gitkeep
├── docs
├── example
│ ├── example.csv
│ └── example.txt
└── media
│ └── preview.gif
├── imapsync_binaries
├── bin
│ └── imapsync
├── darwin
│ └── imapsync
├── ubuntu
│ └── after_installation.sh
├── version.json
└── windows
│ ├── Cook
│ ├── build_exe.bat
│ ├── imapsync
│ ├── install_modules.bat
│ ├── test_cook_exe.bat
│ └── test_cook_src.bat
│ ├── README.txt
│ ├── README_Windows.txt
│ ├── file.txt
│ ├── imapsync.exe
│ ├── imapsync_example.bat
│ └── sync_loop_windows.bat
├── package.json
├── revision.json
├── src
├── index.ejs
├── main
│ ├── imapsync.js
│ ├── index.dev.js
│ ├── index.js
│ ├── menu.js
│ └── updater.js
└── renderer
│ ├── App.vue
│ ├── assets
│ ├── .gitkeep
│ ├── app
│ │ └── icons
│ │ │ ├── 128x128.png
│ │ │ ├── 16x16.png
│ │ │ ├── 24x24.png
│ │ │ ├── 256x256.png
│ │ │ ├── 32x32.png
│ │ │ ├── 48x48.png
│ │ │ ├── 512x512.png
│ │ │ ├── 64x64.png
│ │ │ └── 96x96.png
│ ├── logo.png
│ ├── logo_heart.svg
│ └── logo_sync.svg
│ ├── components
│ ├── About.vue
│ ├── Add
│ │ └── MailboxForm.vue
│ ├── ImportCsvButton.vue
│ ├── MainComponent.vue
│ ├── QueueTable
│ │ ├── QueueTable.vue
│ │ └── QueueTablePassword.vue
│ └── ShellAlikeBox.vue
│ ├── main.js
│ ├── router
│ └── index.js
│ └── store
│ ├── index.js
│ └── modules
│ ├── Counter.js
│ ├── EventBus.js
│ ├── Mailboxes.js
│ ├── ShellHistory.js
│ ├── Version.js
│ └── index.js
├── static
└── .gitkeep
├── test.csv
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "comments": false,
3 | "env": {
4 | "main": {
5 | "presets": [
6 | ["env", {
7 | "targets": { "node": 7 }
8 | }],
9 | "stage-0"
10 | ]
11 | },
12 | "renderer": {
13 | "presets": [
14 | ["env", {
15 | "modules": false
16 | }],
17 | "stage-0"
18 | ]
19 | },
20 | "web": {
21 | "presets": [
22 | ["env", {
23 | "modules": false
24 | }],
25 | "stage-0"
26 | ]
27 | }
28 | },
29 | "plugins": ["transform-runtime"]
30 | }
31 |
--------------------------------------------------------------------------------
/.electron-vue/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | process.env.NODE_ENV = 'production'
4 |
5 | const { say } = require('cfonts')
6 | const chalk = require('chalk')
7 | const del = require('del')
8 | const { spawn } = require('child_process')
9 | const webpack = require('webpack')
10 | const Multispinner = require('multispinner')
11 |
12 |
13 | const mainConfig = require('./webpack.main.config')
14 | const rendererConfig = require('./webpack.renderer.config')
15 | const webConfig = require('./webpack.web.config')
16 |
17 | const doneLog = chalk.bgGreen.white(' DONE ') + ' '
18 | const errorLog = chalk.bgRed.white(' ERROR ') + ' '
19 | const okayLog = chalk.bgBlue.white(' OKAY ') + ' '
20 | const isCI = process.env.CI || false
21 |
22 | if (process.env.BUILD_TARGET === 'clean') clean()
23 | else if (process.env.BUILD_TARGET === 'web') web()
24 | else build()
25 |
26 | function clean () {
27 | del.sync(['build/*', '!build/icons', '!build/icons/icon.*'])
28 | console.log(`\n${doneLog}\n`)
29 | process.exit()
30 | }
31 |
32 | function build () {
33 | greeting()
34 |
35 | del.sync(['dist/electron/*', '!.gitkeep'])
36 |
37 | const tasks = ['main', 'renderer']
38 | const m = new Multispinner(tasks, {
39 | preText: 'building',
40 | postText: 'process'
41 | })
42 |
43 | let results = ''
44 |
45 | m.on('success', () => {
46 | process.stdout.write('\x1B[2J\x1B[0f')
47 | console.log(`\n\n${results}`)
48 | console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
49 | process.exit()
50 | })
51 |
52 | pack(mainConfig).then(result => {
53 | results += result + '\n\n'
54 | m.success('main')
55 | }).catch(err => {
56 | m.error('main')
57 | console.log(`\n ${errorLog}failed to build main process`)
58 | console.error(`\n${err}\n`)
59 | process.exit(1)
60 | })
61 |
62 | pack(rendererConfig).then(result => {
63 | results += result + '\n\n'
64 | m.success('renderer')
65 | }).catch(err => {
66 | m.error('renderer')
67 | console.log(`\n ${errorLog}failed to build renderer process`)
68 | console.error(`\n${err}\n`)
69 | process.exit(1)
70 | })
71 | }
72 |
73 | function pack (config) {
74 | return new Promise((resolve, reject) => {
75 | webpack(config, (err, stats) => {
76 | if (err) reject(err.stack || err)
77 | else if (stats.hasErrors()) {
78 | let err = ''
79 |
80 | stats.toString({
81 | chunks: false,
82 | colors: true
83 | })
84 | .split(/\r?\n/)
85 | .forEach(line => {
86 | err += ` ${line}\n`
87 | })
88 |
89 | reject(err)
90 | } else {
91 | resolve(stats.toString({
92 | chunks: false,
93 | colors: true
94 | }))
95 | }
96 | })
97 | })
98 | }
99 |
100 | function web () {
101 | del.sync(['dist/web/*', '!.gitkeep'])
102 | webpack(webConfig, (err, stats) => {
103 | if (err || stats.hasErrors()) console.log(err)
104 |
105 | console.log(stats.toString({
106 | chunks: false,
107 | colors: true
108 | }))
109 |
110 | process.exit()
111 | })
112 | }
113 |
114 | function greeting () {
115 | const cols = process.stdout.columns
116 | let text = ''
117 |
118 | if (cols > 85) text = 'lets-build'
119 | else if (cols > 60) text = 'lets-|build'
120 | else text = false
121 |
122 | if (text && !isCI) {
123 | say(text, {
124 | colors: ['yellow'],
125 | font: 'simple3d',
126 | space: false
127 | })
128 | } else console.log(chalk.yellow.bold('\n lets-build'))
129 | console.log()
130 | }
131 |
--------------------------------------------------------------------------------
/.electron-vue/dev-client.js:
--------------------------------------------------------------------------------
1 | const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
2 |
3 | hotClient.subscribe(event => {
4 | /**
5 | * Reload browser when HTMLWebpackPlugin emits a new index.html
6 | *
7 | * Currently disabled until jantimon/html-webpack-plugin#680 is resolved.
8 | * https://github.com/SimulatedGREG/electron-vue/issues/437
9 | * https://github.com/jantimon/html-webpack-plugin/issues/680
10 | */
11 | // if (event.action === 'reload') {
12 | // window.location.reload()
13 | // }
14 |
15 | /**
16 | * Notify `mainWindow` when `main` process is compiling,
17 | * giving notice for an expected reload of the `electron` process
18 | */
19 | if (event.action === 'compiling') {
20 | document.body.innerHTML += `
21 |
34 |
35 |
36 | Compiling Main Process...
37 |
38 | `
39 | }
40 | })
41 |
--------------------------------------------------------------------------------
/.electron-vue/dev-runner.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const chalk = require('chalk')
4 | const electron = require('electron')
5 | const path = require('path')
6 | const { say } = require('cfonts')
7 | const { spawn } = require('child_process')
8 | const webpack = require('webpack')
9 | const WebpackDevServer = require('webpack-dev-server')
10 | const webpackHotMiddleware = require('webpack-hot-middleware')
11 |
12 | const mainConfig = require('./webpack.main.config')
13 | const rendererConfig = require('./webpack.renderer.config')
14 |
15 | let electronProcess = null
16 | let manualRestart = false
17 | let hotMiddleware
18 |
19 | function logStats (proc, data) {
20 | let log = ''
21 |
22 | log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`)
23 | log += '\n\n'
24 |
25 | if (typeof data === 'object') {
26 | data.toString({
27 | colors: true,
28 | chunks: false
29 | }).split(/\r?\n/).forEach(line => {
30 | log += ' ' + line + '\n'
31 | })
32 | } else {
33 | log += ` ${data}\n`
34 | }
35 |
36 | log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n'
37 |
38 | console.log(log)
39 | }
40 |
41 | function startRenderer () {
42 | return new Promise((resolve, reject) => {
43 | rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
44 |
45 | const compiler = webpack(rendererConfig)
46 | hotMiddleware = webpackHotMiddleware(compiler, {
47 | log: false,
48 | heartbeat: 2500
49 | })
50 |
51 | compiler.plugin('compilation', compilation => {
52 | compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
53 | hotMiddleware.publish({ action: 'reload' })
54 | cb()
55 | })
56 | })
57 |
58 | compiler.plugin('done', stats => {
59 | logStats('Renderer', stats)
60 | })
61 |
62 | const server = new WebpackDevServer(
63 | compiler,
64 | {
65 | contentBase: path.join(__dirname, '../'),
66 | quiet: true,
67 | before (app, ctx) {
68 | app.use(hotMiddleware)
69 | ctx.middleware.waitUntilValid(() => {
70 | resolve()
71 | })
72 | }
73 | }
74 | )
75 |
76 | server.listen(9080)
77 | })
78 | }
79 |
80 | function startMain () {
81 | return new Promise((resolve, reject) => {
82 | mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
83 |
84 | const compiler = webpack(mainConfig)
85 |
86 | compiler.plugin('watch-run', (compilation, done) => {
87 | logStats('Main', chalk.white.bold('compiling...'))
88 | hotMiddleware.publish({ action: 'compiling' })
89 | done()
90 | })
91 |
92 | compiler.watch({}, (err, stats) => {
93 | if (err) {
94 | console.log(err)
95 | return
96 | }
97 |
98 | logStats('Main', stats)
99 |
100 | if (electronProcess && electronProcess.kill) {
101 | manualRestart = true
102 | process.kill(electronProcess.pid)
103 | electronProcess = null
104 | startElectron()
105 |
106 | setTimeout(() => {
107 | manualRestart = false
108 | }, 5000)
109 | }
110 |
111 | resolve()
112 | })
113 | })
114 | }
115 |
116 | function startElectron () {
117 | electronProcess = spawn(electron, ['--inspect=5858', path.join(__dirname, '../dist/electron/main.js')])
118 |
119 | electronProcess.stdout.on('data', data => {
120 | electronLog(data, 'blue')
121 | })
122 | electronProcess.stderr.on('data', data => {
123 | electronLog(data, 'red')
124 | })
125 |
126 | electronProcess.on('close', () => {
127 | if (!manualRestart) process.exit()
128 | })
129 | }
130 |
131 | function electronLog (data, color) {
132 | let log = ''
133 | data = data.toString().split(/\r?\n/)
134 | data.forEach(line => {
135 | log += ` ${line}\n`
136 | })
137 | if (/[0-9A-z]+/.test(log)) {
138 | console.log(
139 | chalk[color].bold('┏ Electron -------------------') +
140 | '\n\n' +
141 | log +
142 | chalk[color].bold('┗ ----------------------------') +
143 | '\n'
144 | )
145 | }
146 | }
147 |
148 | function greeting () {
149 | const cols = process.stdout.columns
150 | let text = ''
151 |
152 | if (cols > 104) text = 'electron-vue'
153 | else if (cols > 76) text = 'electron-|vue'
154 | else text = false
155 |
156 | if (text) {
157 | say(text, {
158 | colors: ['yellow'],
159 | font: 'simple3d',
160 | space: false
161 | })
162 | } else console.log(chalk.yellow.bold('\n electron-vue'))
163 | console.log(chalk.blue(' getting ready...') + '\n')
164 | }
165 |
166 | function init () {
167 | greeting()
168 |
169 | Promise.all([startRenderer(), startMain()])
170 | .then(() => {
171 | startElectron()
172 | })
173 | .catch(err => {
174 | console.error(err)
175 | })
176 | }
177 |
178 | init()
179 |
--------------------------------------------------------------------------------
/.electron-vue/revision.js:
--------------------------------------------------------------------------------
1 | let fs = require('fs')
2 | let git = require('git-rev-sync')
3 | let app = require('../package.json')
4 |
5 | let revision = {
6 | rev: git.short(),
7 | version: app.version + '.' + git.short(),
8 | date: (new Date()).toLocaleString()
9 | };
10 |
11 | fs.writeFileSync('revision.json', JSON.stringify(revision, null, 2));
12 |
13 | console.log(revision.version);
--------------------------------------------------------------------------------
/.electron-vue/webpack.main.config.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | process.env.BABEL_ENV = 'main'
4 |
5 | const path = require('path')
6 | const { dependencies } = require('../package.json')
7 | const webpack = require('webpack')
8 |
9 | const BabiliWebpackPlugin = require('babili-webpack-plugin')
10 |
11 | let mainConfig = {
12 | entry: {
13 | main: path.join(__dirname, '../src/main/index.js')
14 | },
15 | externals: [
16 | ...Object.keys(dependencies || {})
17 | ],
18 | module: {
19 | rules: [
20 | {
21 | test: /\.(js)$/,
22 | enforce: 'pre',
23 | exclude: /node_modules/,
24 | use: {
25 | loader: 'eslint-loader',
26 | options: {
27 | formatter: require('eslint-friendly-formatter')
28 | }
29 | }
30 | },
31 | {
32 | test: /\.js$/,
33 | use: 'babel-loader',
34 | exclude: /node_modules/
35 | },
36 | {
37 | test: /\.node$/,
38 | use: 'node-loader'
39 | }
40 | ]
41 | },
42 | node: {
43 | __dirname: process.env.NODE_ENV !== 'production',
44 | __filename: process.env.NODE_ENV !== 'production'
45 | },
46 | output: {
47 | filename: '[name].js',
48 | libraryTarget: 'commonjs2',
49 | path: path.join(__dirname, '../dist/electron')
50 | },
51 | plugins: [
52 | new webpack.NoEmitOnErrorsPlugin()
53 | ],
54 | resolve: {
55 | extensions: ['.js', '.json', '.node']
56 | },
57 | target: 'electron-main'
58 | }
59 |
60 | /**
61 | * Adjust mainConfig for development settings
62 | */
63 | if (process.env.NODE_ENV !== 'production') {
64 | mainConfig.plugins.push(
65 | new webpack.DefinePlugin({
66 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
67 | })
68 | )
69 | }
70 |
71 | /**
72 | * Adjust mainConfig for production settings
73 | */
74 | if (process.env.NODE_ENV === 'production') {
75 | mainConfig.plugins.push(
76 | new BabiliWebpackPlugin(),
77 | new webpack.DefinePlugin({
78 | 'process.env.NODE_ENV': '"production"'
79 | })
80 | )
81 | }
82 |
83 | module.exports = mainConfig
84 |
--------------------------------------------------------------------------------
/.electron-vue/webpack.renderer.config.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | process.env.BABEL_ENV = 'renderer'
4 |
5 | const path = require('path')
6 | const { dependencies } = require('../package.json')
7 | const webpack = require('webpack')
8 |
9 | const BabiliWebpackPlugin = require('babili-webpack-plugin')
10 | const CopyWebpackPlugin = require('copy-webpack-plugin')
11 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
12 | const HtmlWebpackPlugin = require('html-webpack-plugin')
13 |
14 | /**
15 | * List of node_modules to include in webpack bundle
16 | *
17 | * Required for specific packages like Vue UI libraries
18 | * that provide pure *.vue files that need compiling
19 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
20 | */
21 | let whiteListedModules = ['vue']
22 |
23 | let rendererConfig = {
24 | devtool: '#cheap-module-eval-source-map',
25 | entry: {
26 | renderer: path.join(__dirname, '../src/renderer/main.js')
27 | },
28 | externals: [
29 | ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
30 | ],
31 | module: {
32 | rules: [
33 | {
34 | test: /\.(js|vue)$/,
35 | enforce: 'pre',
36 | exclude: /node_modules/,
37 | use: {
38 | loader: 'eslint-loader',
39 | options: {
40 | formatter: require('eslint-friendly-formatter')
41 | }
42 | }
43 | },
44 | {
45 | test: /\.css$/,
46 | use: ExtractTextPlugin.extract({
47 | fallback: 'style-loader',
48 | use: 'css-loader'
49 | })
50 | },
51 | {
52 | test: /\.html$/,
53 | use: 'vue-html-loader'
54 | },
55 | {
56 | test: /\.js$/,
57 | use: 'babel-loader',
58 | exclude: /node_modules/
59 | },
60 | {
61 | test: /\.node$/,
62 | use: 'node-loader'
63 | },
64 | {
65 | test: /\.vue$/,
66 | use: {
67 | loader: 'vue-loader',
68 | options: {
69 | extractCSS: process.env.NODE_ENV === 'production',
70 | loaders: {
71 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
72 | scss: 'vue-style-loader!css-loader!sass-loader'
73 | }
74 | }
75 | }
76 | },
77 | {
78 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
79 | use: {
80 | loader: 'url-loader',
81 | query: {
82 | limit: 10000,
83 | name: 'imgs/[name]--[folder].[ext]'
84 | }
85 | }
86 | },
87 | {
88 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
89 | loader: 'url-loader',
90 | options: {
91 | limit: 10000,
92 | name: 'media/[name]--[folder].[ext]'
93 | }
94 | },
95 | {
96 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
97 | use: {
98 | loader: 'url-loader',
99 | query: {
100 | limit: 10000,
101 | name: 'fonts/[name]--[folder].[ext]'
102 | }
103 | }
104 | }
105 | ]
106 | },
107 | node: {
108 | __dirname: process.env.NODE_ENV !== 'production',
109 | __filename: process.env.NODE_ENV !== 'production'
110 | },
111 | plugins: [
112 | new ExtractTextPlugin('styles.css'),
113 | new HtmlWebpackPlugin({
114 | filename: 'index.html',
115 | template: path.resolve(__dirname, '../src/index.ejs'),
116 | minify: {
117 | collapseWhitespace: true,
118 | removeAttributeQuotes: true,
119 | removeComments: true
120 | },
121 | nodeModules: process.env.NODE_ENV !== 'production'
122 | ? path.resolve(__dirname, '../node_modules')
123 | : false
124 | }),
125 | new webpack.HotModuleReplacementPlugin(),
126 | new webpack.NoEmitOnErrorsPlugin()
127 | ],
128 | output: {
129 | filename: '[name].js',
130 | libraryTarget: 'commonjs2',
131 | path: path.join(__dirname, '../dist/electron')
132 | },
133 | resolve: {
134 | alias: {
135 | '@': path.join(__dirname, '../src/renderer'),
136 | 'vue$': 'vue/dist/vue.esm.js'
137 | },
138 | extensions: ['.js', '.vue', '.json', '.css', '.node']
139 | },
140 | target: 'electron-renderer'
141 | }
142 |
143 | /**
144 | * Adjust rendererConfig for development settings
145 | */
146 | if (process.env.NODE_ENV !== 'production') {
147 | rendererConfig.plugins.push(
148 | new webpack.DefinePlugin({
149 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
150 | })
151 | )
152 | }
153 |
154 | /**
155 | * Adjust rendererConfig for production settings
156 | */
157 | if (process.env.NODE_ENV === 'production') {
158 | rendererConfig.devtool = ''
159 |
160 | rendererConfig.plugins.push(
161 | new BabiliWebpackPlugin(),
162 | new CopyWebpackPlugin([
163 | {
164 | from: path.join(__dirname, '../static'),
165 | to: path.join(__dirname, '../dist/electron/static'),
166 | ignore: ['.*']
167 | }
168 | ]),
169 | new webpack.DefinePlugin({
170 | 'process.env.NODE_ENV': '"production"'
171 | }),
172 | new webpack.LoaderOptionsPlugin({
173 | minimize: true
174 | })
175 | )
176 | }
177 |
178 | module.exports = rendererConfig
179 |
--------------------------------------------------------------------------------
/.electron-vue/webpack.web.config.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | process.env.BABEL_ENV = 'web'
4 |
5 | const path = require('path')
6 | const webpack = require('webpack')
7 |
8 | const BabiliWebpackPlugin = require('babili-webpack-plugin')
9 | const CopyWebpackPlugin = require('copy-webpack-plugin')
10 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
11 | const HtmlWebpackPlugin = require('html-webpack-plugin')
12 |
13 | let webConfig = {
14 | devtool: '#cheap-module-eval-source-map',
15 | entry: {
16 | web: path.join(__dirname, '../src/renderer/main.js')
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.(js|vue)$/,
22 | enforce: 'pre',
23 | exclude: /node_modules/,
24 | use: {
25 | loader: 'eslint-loader',
26 | options: {
27 | formatter: require('eslint-friendly-formatter')
28 | }
29 | }
30 | },
31 | {
32 | test: /\.css$/,
33 | use: ExtractTextPlugin.extract({
34 | fallback: 'style-loader',
35 | use: 'css-loader'
36 | })
37 | },
38 | {
39 | test: /\.html$/,
40 | use: 'vue-html-loader'
41 | },
42 | {
43 | test: /\.js$/,
44 | use: 'babel-loader',
45 | include: [ path.resolve(__dirname, '../src/renderer') ],
46 | exclude: /node_modules/
47 | },
48 | {
49 | test: /\.vue$/,
50 | use: {
51 | loader: 'vue-loader',
52 | options: {
53 | extractCSS: true,
54 | loaders: {
55 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
56 | scss: 'vue-style-loader!css-loader!sass-loader'
57 | }
58 | }
59 | }
60 | },
61 | {
62 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
63 | use: {
64 | loader: 'url-loader',
65 | query: {
66 | limit: 10000,
67 | name: 'imgs/[name].[ext]'
68 | }
69 | }
70 | },
71 | {
72 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
73 | use: {
74 | loader: 'url-loader',
75 | query: {
76 | limit: 10000,
77 | name: 'fonts/[name].[ext]'
78 | }
79 | }
80 | }
81 | ]
82 | },
83 | plugins: [
84 | new ExtractTextPlugin('styles.css'),
85 | new HtmlWebpackPlugin({
86 | filename: 'index.html',
87 | template: path.resolve(__dirname, '../src/index.ejs'),
88 | minify: {
89 | collapseWhitespace: true,
90 | removeAttributeQuotes: true,
91 | removeComments: true
92 | },
93 | nodeModules: false
94 | }),
95 | new webpack.DefinePlugin({
96 | 'process.env.IS_WEB': 'true'
97 | }),
98 | new webpack.HotModuleReplacementPlugin(),
99 | new webpack.NoEmitOnErrorsPlugin()
100 | ],
101 | output: {
102 | filename: '[name].js',
103 | path: path.join(__dirname, '../dist/web')
104 | },
105 | resolve: {
106 | alias: {
107 | '@': path.join(__dirname, '../src/renderer'),
108 | 'vue$': 'vue/dist/vue.esm.js'
109 | },
110 | extensions: ['.js', '.vue', '.json', '.css']
111 | },
112 | target: 'web'
113 | }
114 |
115 | /**
116 | * Adjust webConfig for production settings
117 | */
118 | if (process.env.NODE_ENV === 'production') {
119 | webConfig.devtool = ''
120 |
121 | webConfig.plugins.push(
122 | new BabiliWebpackPlugin(),
123 | new CopyWebpackPlugin([
124 | {
125 | from: path.join(__dirname, '../static'),
126 | to: path.join(__dirname, '../dist/web/static'),
127 | ignore: ['.*']
128 | }
129 | ]),
130 | new webpack.DefinePlugin({
131 | 'process.env.NODE_ENV': '"production"'
132 | }),
133 | new webpack.LoaderOptionsPlugin({
134 | minimize: true
135 | })
136 | )
137 | }
138 |
139 | module.exports = webConfig
140 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/.eslintignore
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: 'babel-eslint',
4 | parserOptions: {
5 | sourceType: 'module'
6 | },
7 | env: {
8 | browser: true,
9 | node: true
10 | },
11 | extends: 'standard',
12 | globals: {
13 | __static: true
14 | },
15 | plugins: [
16 | 'html'
17 | ],
18 | 'rules': {
19 | // allow paren-less arrow functions
20 | 'arrow-parens': 0,
21 | // allow async-await
22 | 'generator-star-spacing': 0,
23 | // allow debugger during development
24 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
25 | 'indent': 'off',
26 | 'handle-callback-err': 'off',
27 | 'brace-style': 'off',
28 | 'semi': ['error', 'always'],
29 | 'no-trailing-spaces': 'off',
30 | 'space-before-function-paren': 'off'
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | imapsync_binaries/* linguist-vendored
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist/electron/*
3 | dist/web/*
4 | build/*
5 | !build/icons
6 | /node_modules/
7 | npm-debug.log
8 | npm-debug.log.*
9 | thumbs.db
10 | !.gitkeep
11 | /.idea/
12 | .imapsync/downloads
--------------------------------------------------------------------------------
/.imapsync/upgrade.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const axios = require('axios');
6 | const impasyncVersion = require('../imapsync_binaries/version');
7 | const child = require('child_process');
8 | const del = require('del');
9 |
10 | const downloadsPath = path.resolve(__dirname, 'downloads');
11 | const currentVersion = impasyncVersion.version;
12 | let latestVersion = null;
13 |
14 | axios.get('https://imapsync.lamiral.info/VERSION')
15 | .then(({data}) => {
16 | latestVersion = data;
17 |
18 | if (currentVersion != latestVersion) {
19 | upgrade();
20 | } else {
21 | console.log('Already up-to-date');
22 | }
23 | })
24 | .catch(error => console.error(error));
25 |
26 | function init() {
27 | cleanup();
28 |
29 | if (!fs.existsSync(downloadsPath)) {
30 | fs.mkdir(downloadsPath, {}, err => {
31 | if (err) throw err
32 | });
33 | }
34 |
35 | }
36 |
37 | function upgrade() {
38 | init();
39 |
40 | console.log(`Upgrade from v${currentVersion} to v${latestVersion}`);
41 |
42 | let sourcePath = null;
43 | // Download perl script
44 | messageDownloading('perl script');
45 | sourcePath = downloadBinary('imapsync');
46 | move(sourcePath, 'bin/imapsync');
47 | messageUpgraded('perl script');
48 |
49 | // Download darwin binary
50 | messageDownloading('darwin binary');
51 | sourcePath = downloadBinary('imapsync_bin_Darwin');
52 | move(sourcePath, 'darwin/imapsync');
53 | messageUpgraded('darwin binary');
54 |
55 | // Download windows binary
56 | messageDownloading('windows binary');
57 | const zipFilename = `imapsync_${latestVersion}`;
58 | const extractFolder = path.resolve(downloadsPath, 'imapsync_extracted/');
59 | sourcePath = downloadBinary(zipFilename + '.zip');
60 | child.execSync(`unzip -q ${sourcePath} -d ${extractFolder}`);
61 | move(path.resolve(extractFolder, zipFilename, 'imapsync.exe'), 'windows/imapsync.exe', false);
62 | messageUpgraded('windows binary');
63 |
64 | finalize();
65 | }
66 |
67 | function downloadBinary(fileName) {
68 | child.execSync(`cd ${downloadsPath} && curl -LO# https://imapsync.lamiral.info/dist/${fileName}`);
69 | return path.resolve(downloadsPath, fileName);
70 | }
71 |
72 | function move(source, target, setPermissions=true) {
73 | if (setPermissions) {
74 | child.execSync('chmod a+x ' + source);
75 | }
76 |
77 | fs.renameSync(
78 | source,
79 | path.resolve(__dirname, '../imapsync_binaries/', target)
80 | );
81 | }
82 |
83 | function finalize() {
84 | fs.writeFileSync(
85 | path.resolve(__dirname, '../imapsync_binaries/version.json'),
86 | JSON.stringify({version: latestVersion.toString()}, null, 2)
87 | );
88 |
89 | cleanup();
90 | }
91 |
92 | function cleanup() {
93 | del.sync([downloadsPath]);
94 | }
95 |
96 | function messageDownloading(binName) {
97 | console.log(`Downloading ${binName}...`);
98 | }
99 |
100 | function messageUpgraded(binName) {
101 | console.log(`Successfully upgraded ${binName}!`);
102 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | matrix:
2 | include:
3 | - os: osx
4 | osx_image: xcode9.2
5 | language: node_js
6 | node_js: "10"
7 | env:
8 | - ELECTRON_CACHE=$HOME/.cache/electron
9 | - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder
10 |
11 | - os: linux
12 | services: docker
13 | language: generic
14 |
15 | cache:
16 | directories:
17 | - node_modules
18 | - $HOME/.cache/electron
19 | - $HOME/.cache/electron-builder
20 |
21 | before_install:
22 | - |
23 | if [ "$TRAVIS_OS_NAME" == "osx" ]; then
24 | mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v2.3.1/git-lfs-$([ "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-2.3.1.tar.gz | tar -xz -C /tmp/git-lfs --strip-components 1
25 | export PATH="/tmp/git-lfs:$PATH"
26 | fi
27 | before_script:
28 | - git lfs pull
29 |
30 | script:
31 | - |
32 | if [ "$TRAVIS_OS_NAME" == "linux" ]; then
33 | docker run --rm \
34 | $(env | \
35 | grep -Eo '^[^\s=]*(DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|_TOKEN|_KEY|AWS_|STRIP|BUILD_)[^\s=]*' | \
36 | sed '/^$/d;s/^/-e /' | \
37 | paste -sd ' ' \
38 | ) \
39 | -v ${PWD}:/project \
40 | -v ~/.cache/electron:/root/.cache/electron \
41 | -v ~/.cache/electron-builder:/root/.cache/electron-builder \
42 | electronuserland/builder:wine \
43 | /bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn release --linux --win"
44 | else
45 | yarn release
46 | fi
47 | before_cache:
48 | - rm -rf $HOME/.cache/electron-builder/wine
49 |
50 | branches:
51 | except:
52 | - "/^v\\d+\\.\\d+\\.\\d+$/"
53 | only:
54 | - master
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Rida Amirini
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALInNGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImapSync Client [](https://travis-ci.org/ridaamirini/ImapSyncClient)
2 |
3 | [](http://forthebadge.com)
4 | [](http://forthebadge.com)
5 | [](http://forthebadge.com)
6 | [](http://forthebadge.com)
7 | [](http://forthebadge.com)
8 |
9 | > It's only an Internet Message Access Protocol Synchronization Client
10 |
11 | ## Overview
12 |
13 | ImapSync Client is an Email IMAP tool for syncing, copying and migrating email
14 | mailboxes between two imap servers, one way, and without duplicates.
15 |
16 | ## Download
17 | Download the latest version from the [releases](https://github.com/ridaamirini/imapsyncclient/releases/latest) page.
18 |
19 | _**Warning:** Note that versions below 1.0 will not work anymore. Please update to the latest version._
20 |
21 | ## Demo
22 |
23 | 
24 |
25 | ### Import Mailboxes from CSV :page_facing_up:
26 | - [Example file *.csv](https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/1.0/docs/example/example.csv)
27 | - [Example file *.txt](https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/1.0/docs/example/example.txt)
28 |
29 | #### Build Setup
30 |
31 | ``` bash
32 | # install dependencies
33 | npm install
34 |
35 | # serve with hot reload at localhost:9080
36 | npm run dev
37 |
38 | # build electron application for production
39 | npm run build
40 |
41 |
42 | # lint all JS/Vue component files in `src/`
43 | npm run lint
44 |
45 | ```
46 | ## Thanks
47 | ### Front-End
48 | - [Vue.js](https://github.com/vuejs/vue)
49 | - [Electron](https://github.com/electron/electron)
50 | - [ElectronVue](https://github.com/SimulatedGREG/electron-vue)
51 | - [Element](https://github.com/ElemeFE/element)
52 | ### Design inspired by
53 | - [imapsync.love](http://imapsync.love)
54 |
55 | ## TODO
56 | - [x] ~~Remove API dependency~~
57 | - [x] ~~Import Mailboxes from CSV~~
58 |
59 | ## License
60 |
61 | ImapSync Client is licensed under the [MIT License](LICENSE)
62 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 0.1.{build}
2 |
3 | branches:
4 | only:
5 | - master
6 |
7 | image: Visual Studio 2017
8 | platform:
9 | - x64
10 |
11 | cache:
12 | - node_modules
13 | - '%APPDATA%\npm-cache'
14 | - '%USERPROFILE%\.electron'
15 | - '%USERPROFILE%\AppData\Local\Yarn\cache'
16 |
17 | init:
18 | - git config --global core.autocrlf input
19 |
20 | install:
21 | - ps: Install-Product node 8 x64
22 | - choco install yarn --ignore-dependencies
23 | - git reset --hard HEAD
24 | - yarn
25 | - node --version
26 |
27 | build_script:
28 | - yarn build
29 |
30 | test: off
31 |
--------------------------------------------------------------------------------
/build/icons/256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/build/icons/256x256.png
--------------------------------------------------------------------------------
/build/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/build/icons/icon.icns
--------------------------------------------------------------------------------
/build/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/build/icons/icon.ico
--------------------------------------------------------------------------------
/dist/electron/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/dist/electron/.gitkeep
--------------------------------------------------------------------------------
/dist/web/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/dist/web/.gitkeep
--------------------------------------------------------------------------------
/docs/example/example.csv:
--------------------------------------------------------------------------------
1 | # Example example.csv for imapsync massive migration.
2 | #
3 | # Each line contains 6 columns, columns are parameters for
4 | # --host1 --user1 --password1 --host2 --user2 --password2
5 | # and a trailing empty fake column to avoid CR LF part going
6 | # in the 6th parameter password2. Don't forget the last semicolon.
7 | #
8 | # Lines starting with a # are comments and ignored
9 | # Blank lines are ignored as well
10 |
11 |
12 | # Now the data example
13 | host001_1;user001_1;password001_1;host001_2;user001_2;password001_2;
14 | host002_1;user002_1;password002_1;host002_2;user002_2;password002_2;
15 | host003_1;user003_1;password003_1;host003_2;user003_2;password003_2;
16 |
17 | # Another comment blabla
18 | host004_1;user004_1;password004_1;host004_2;user004_2;password004_2;
19 |
20 | # This last example is a real one, ie, truly working in the real world.
21 | test1.lamiral.info;test1;secret1;test2.lamiral.info;test2;secret2;
--------------------------------------------------------------------------------
/docs/example/example.txt:
--------------------------------------------------------------------------------
1 | # Example example.txt for imapsync massive migration.
2 | #
3 | # Each line contains 6 columns, columns are parameters for
4 | # --host1 --user1 --password1 --host2 --user2 --password2
5 | # and a trailing empty fake column to avoid CR LF part going
6 | # in the 6th parameter password2. Don't forget the last semicolon.
7 | #
8 | # Lines starting with a # are comments and ignored
9 | # Blank lines are ignored as well
10 |
11 |
12 | # Now the data example
13 | host001_1;user001_1;password001_1;host001_2;user001_2;password001_2;
14 | host002_1;user002_1;password002_1;host002_2;user002_2;password002_2;
15 | host003_1;user003_1;password003_1;host003_2;user003_2;password003_2;
16 |
17 | # Another comment blabla
18 | host004_1;user004_1;password004_1;host004_2;user004_2;password004_2;
19 |
20 | # This last example is a real one, ie, truly working in the real world.
21 | test1.lamiral.info;test1;secret1;test2.lamiral.info;test2;secret2;
--------------------------------------------------------------------------------
/docs/media/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/docs/media/preview.gif
--------------------------------------------------------------------------------
/imapsync_binaries/darwin/imapsync:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/imapsync_binaries/darwin/imapsync
--------------------------------------------------------------------------------
/imapsync_binaries/ubuntu/after_installation.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # =================================================
4 | # = Installing imapsync on Ubuntu 16.04 or higher =
5 | # =================================================
6 |
7 | # Here is the command to install imapsync dependencies,
8 | # you need root privilege to run them.
9 | # This command installs standard Ubuntu packages:
10 |
11 | sudo apt-get install \
12 | libauthen-ntlm-perl \
13 | libclass-load-perl \
14 | libcrypt-ssleay-perl \
15 | libdata-uniqid-perl \
16 | libdigest-hmac-perl \
17 | libdist-checkconflicts-perl \
18 | libfile-copy-recursive-perl \
19 | libio-compress-perl \
20 | libio-socket-inet6-perl \
21 | libio-socket-ssl-perl \
22 | libio-tee-perl \
23 | libmail-imapclient-perl \
24 | libmodule-scandeps-perl \
25 | libnet-ssleay-perl \
26 | libpar-packer-perl \
27 | libreadonly-perl \
28 | libregexp-common-perl \
29 | libssl-dev \
30 | libsys-meminfo-perl \
31 | libterm-readkey-perl \
32 | libtest-fatal-perl \
33 | libtest-mock-guard-perl \
34 | libtest-pod-perl \
35 | libtest-requires-perl \
36 | libtest-simple-perl \
37 | libunicode-string-perl \
38 | liburi-perl \
39 | libtest-nowarnings-perl \
40 | libtest-deep-perl \
41 | libtest-warn-perl \
42 | make \
43 | cpanminus
44 |
45 | # You can easily detect any missing Perl modules via the prerequisites_imapsync script
46 | # wget -N https://imapsync.lamiral.info/prerequisites_imapsync
47 | # sh prerequisites_imapsync
--------------------------------------------------------------------------------
/imapsync_binaries/version.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.977"
3 | }
--------------------------------------------------------------------------------
/imapsync_binaries/windows/Cook/build_exe.bat:
--------------------------------------------------------------------------------
1 |
2 | REM $Id: build_exe.bat,v 1.48 2018/02/06 13:12:47 gilles Exp gilles $
3 |
4 | @SETLOCAL
5 | @ECHO Currently running through %0 %*
6 |
7 | @ECHO Building imapsync.exe
8 |
9 | @REM the following command change current directory to the dirname of the current batch pathname
10 | CD /D %~dp0
11 |
12 | REM Remove the error file because its existence means an error occurred during this script execution
13 | IF EXIST LOG_bat\%~nx0.txt DEL LOG_bat\%~nx0.txt
14 |
15 |
16 | CALL :handle_error CALL :detect_perl
17 | CALL :handle_error CALL :check_modules
18 | CALL :handle_error CALL :pp_exe
19 |
20 |
21 | @ENDLOCAL
22 | EXIT /B
23 |
24 |
25 | :pp_exe
26 | @SETLOCAL
27 | @REM CALL pp -o imapsync.exe --link libeay32_.dll --link zlib1_.dll --link ssleay32_.dll .\imapsync
28 | IF %PROCESSOR_ARCHITECTURE% == x86 (
29 | CALL pp -o imapsync.exe -M Test2::Formatter -M Test2::Formatter::TAP -M Test2::Event -M Test2::Event::Info --link zlib1_.dll --link libcrypto-1_1_.dll --link libssl-1_1_.dll .\imapsync
30 | REM CALL pp -o imapsync.exe -M Test2::Formatter -M Test2::Formatter::TAP -M Test2::Event -M Test2::Event::Info --link zlib1_.dll .\imapsync
31 | ) ELSE (
32 | CALL pp -o imapsync.exe -M Test2::Formatter -M Test2::Formatter::TAP -M Test2::Event -M Test2::Event::Info .\imapsync
33 | )
34 | @ENDLOCAL
35 | EXIT /B
36 |
37 |
38 |
39 |
40 | ::------------------------------------------------------
41 | ::--------------- Detect Perl --------------------------
42 | :detect_perl
43 | @SETLOCAL
44 | perl -v
45 | @ENDLOCAL
46 | EXIT /B
47 | ::------------------------------------------------------
48 |
49 |
50 | ::------------------------------------------------------
51 | ::--------------- Check modules are here --------------
52 | :check_modules
53 | @SETLOCAL
54 | perl ^
55 | -mTest::MockObject ^
56 | -mPAR::Packer ^
57 | -mReadonly ^
58 | -mAuthen::NTLM ^
59 | -mData::Dumper ^
60 | -mData::Uniqid ^
61 | -mDigest::HMAC_MD5 ^
62 | -mDigest::HMAC_SHA1 ^
63 | -mDigest::MD5 ^
64 | -mFile::Copy::Recursive ^
65 | -mFile::Spec ^
66 | -mIO::Socket ^
67 | -mIO::Socket::INET ^
68 | -mIO::Socket::IP ^
69 | -mIO::Socket::SSL ^
70 | -mIO::Tee ^
71 | -mMail::IMAPClient ^
72 | -mRegexp::Common ^
73 | -mTerm::ReadKey ^
74 | -mTime::Local ^
75 | -mUnicode::String ^
76 | -mURI::Escape ^
77 | -mJSON::WebToken ^
78 | -mLWP::UserAgent ^
79 | -mHTML::Entities ^
80 | -mJSON ^
81 | -mCrypt::OpenSSL::RSA ^
82 | -mEncode::Byte ^
83 | -e ''
84 | IF ERRORLEVEL 1 CALL .\install_modules.bat
85 | @ENDLOCAL
86 | EXIT /B
87 | ::------------------------------------------------------
88 |
89 |
90 |
91 |
92 | ::------------------------------------------------------
93 | ::--------------- Handle error -------------------------
94 | :handle_error
95 | SETLOCAL
96 | ECHO IN %0 with parameters %*
97 | %*
98 | SET CMD_RETURN=%ERRORLEVEL%
99 |
100 | IF %CMD_RETURN% EQU 0 (
101 | ECHO GOOD END
102 | ) ELSE (
103 | ECHO BAD END
104 | IF NOT EXIST LOG_bat MKDIR LOG_bat
105 | ECHO Failure calling: %* >> LOG_bat\%~nx0.txt
106 | )
107 | ENDLOCAL
108 | EXIT /B
109 | ::------------------------------------------------------
110 |
--------------------------------------------------------------------------------
/imapsync_binaries/windows/Cook/install_modules.bat:
--------------------------------------------------------------------------------
1 | REM $Id: install_modules.bat,v 1.34 2018/04/10 00:10:52 gilles Exp gilles $
2 |
3 | ::------------------------------------------------------
4 | ::--------------- Main of install_modules.bat ----------
5 | @SETLOCAL
6 | @ECHO OFF
7 | ECHO Currently running through %0 %*
8 |
9 | @REM Needed with remote ssh
10 | SET SHELL=
11 | SET
12 | ECHO Installing Perl modules for imapsync
13 |
14 | CD /D %~dp0
15 |
16 | CALL :handle_error CALL :detect_perl
17 | CALL :handle_error CALL :update_modules
18 |
19 | @ENDLOCAL
20 | EXIT /B
21 | ::------------------------------------------------------
22 |
23 |
24 | ::------------------------------------------------------
25 | ::--------------- Detect Perl --------------------------
26 | :detect_perl
27 | @SETLOCAL
28 | perl -v
29 | IF ERRORLEVEL 1 ECHO Perl needed. Install Strawberry Perl. Get it at http://strawberryperl.com/ ^
30 | && PAUSE && EXIT 3
31 | ECHO perl is there
32 | @ENDLOCAL
33 | EXIT /B
34 | ::------------------------------------------------------
35 |
36 |
37 | ::------------------------------------------------------
38 | ::---------------- Update modules ----------------------
39 | :update_modules
40 | @SETLOCAL
41 | FOR %%M in ( ^
42 | Regexp::Common ^
43 | Sys::MemInfo ^
44 | Test::MockObject ^
45 | Readonly ^
46 | Authen::NTLM ^
47 | Crypt::SSLeay ^
48 | Data::Uniqid ^
49 | Digest::HMAC_MD5 ^
50 | Digest::HMAC_SHA1 ^
51 | Digest::MD5 ^
52 | File::Copy::Recursive ^
53 | Getopt::ArgvFile ^
54 | Socket6 ^
55 | IO::Socket::INET ^
56 | IO::Socket::INET6 ^
57 | IO::Socket::SSL ^
58 | IO::Tee ^
59 | Mail::IMAPClient ^
60 | Module::ScanDeps ^
61 | Net::SSL ^
62 | PAR::Packer ^
63 | Pod::Usage ^
64 | Test::Pod ^
65 | Unicode::String ^
66 | URI::Escape ^
67 | Crypt::OpenSSL::RSA ^
68 | JSON ^
69 | JSON::WebToken ^
70 | LWP ^
71 | HTML::Entities ^
72 | Encode::Byte ^
73 | ) DO @perl -m%%M -e "print qq{Updating %%M $%%M::VERSION \n}" ^
74 | & cpanm %%M
75 |
76 | ECHO Perl modules for imapsync updated
77 | REM PAUSE
78 | @ECHO Net::SSLeay not updated
79 |
80 | @ENDLOCAL
81 | EXIT /B
82 |
83 |
84 | ::------------------------------------------------------
85 |
86 |
87 | ::------------------------------------------------------
88 | ::----------- Handle errors in LOG_bat\ directory ------
89 | :handle_error
90 | SETLOCAL
91 | ECHO IN %0 with parameters %*
92 | %*
93 | SET CMD_RETURN=%ERRORLEVEL%
94 |
95 | IF %CMD_RETURN% EQU 0 (
96 | ECHO GOOD END
97 | ) ELSE (
98 | ECHO BAD END
99 | IF NOT EXIST LOG_bat MKDIR LOG_bat
100 | ECHO Failure calling with extra %* >> LOG_bat\%~nx0.txt
101 | )
102 | ENDLOCAL
103 | EXIT /B
104 | ::------------------------------------------------------
105 |
106 |
--------------------------------------------------------------------------------
/imapsync_binaries/windows/Cook/test_cook_exe.bat:
--------------------------------------------------------------------------------
1 | REM $Id: test_cook_exe.bat,v 1.4 2017/09/07 00:59:35 gilles Exp gilles $
2 |
3 | cd /D %~dp0
4 |
5 | .\imapsync.exe
6 | @PAUSE
7 | .\imapsync.exe --tests
8 | @PAUSE
9 | .\imapsync.exe --testslive --nossl2
10 | @PAUSE
11 | .\imapsync.exe --testslive6 --nossl2
12 | @ECHO The previous test fails with "Invalid argument" usually (August 2017)
13 | @ECHO Tests ended, bye.
14 | @PAUSE
15 |
16 | @REM EXIT
17 |
--------------------------------------------------------------------------------
/imapsync_binaries/windows/Cook/test_cook_src.bat:
--------------------------------------------------------------------------------
1 | REM $Id: test_cook_src.bat,v 1.3 2017/09/07 00:59:26 gilles Exp gilles $
2 |
3 | cd /D %~dp0
4 |
5 |
6 |
7 | perl .\imapsync
8 | @PAUSE
9 | perl .\imapsync --tests
10 | @PAUSE
11 | perl .\imapsync --testslive
12 | @PAUSE
13 | perl .\imapsync --testslive6
14 | @ECHO Tests for imapsync script are finished, bye!
15 | @PAUSE
--------------------------------------------------------------------------------
/imapsync_binaries/windows/README.txt:
--------------------------------------------------------------------------------
1 | NAME
2 |
3 | imapsync - Email IMAP tool for syncing, copying and migrating email
4 | mailboxes between two imap servers, one way, and without duplicates.
5 |
6 | VERSION
7 |
8 | This documentation refers to Imapsync $Revision: 1.882 $
9 |
10 | USAGE
11 |
12 | To synchronize the source imap account
13 | "test1" on server "test1.lamiral.info" with password "secret1"
14 | to the destination imap account
15 | "test2" on server "test2.lamiral.info" with password "secret2"
16 | do:
17 |
18 | imapsync \
19 | --host1 test1.lamiral.info --user1 test1 --password1 secret1 \
20 | --host2 test2.lamiral.info --user2 test2 --password2 secret2
21 |
22 | DESCRIPTION
23 |
24 | We sometimes need to transfer mailboxes from one imap server to one
25 | another.
26 |
27 | Imapsync command is a tool allowing incremental and recursive imap
28 | transfers from one mailbox to another.
29 |
30 | By default all folders are transferred, recursively, meaning the whole
31 | folder hierarchy is taken, all messages in them, and all messages flags
32 | (\Seen \Answered \Flagged etc.) are synced too.
33 |
34 | Imapsync reduces the amount of data transferred by not transferring a
35 | given message if it resides already on both sides.
36 |
37 | Same specific headers and the transfer is done only once. By default,
38 | the identification headers are "Message-Id:" and "Received:" lines but
39 | this choice can be changed with the --useheader option.
40 |
41 | All flags are preserved, unread messages will stay unread, read ones
42 | will stay read, deleted will stay deleted.
43 |
44 | You can stop the transfer at any time and restart it later, imapsync
45 | works well with bad connections and interruptions, by design.
46 |
47 | You can decide to delete the messages from the source mailbox after a
48 | successful transfer, it can be a good feature when migrating live
49 | mailboxes since messages will be only on one side.
50 |
51 | In that case, use the --delete1 option. Option --delete1 implies also
52 | option --expunge1 so all messages marked deleted on host1 will be really
53 | deleted.
54 |
55 | You can also decide to remove empty folders once all of their messages
56 | have been transferred. Add --delete1emptyfolders to obtain this
57 | behavior.
58 |
59 | A different scenario is synchronizing a mailbox B from another mailbox A
60 | in case you just want to keep a "live" copy of A in B.
61 |
62 | For this, option --delete2 has to be used, it deletes messages in host2
63 | folder B that are not in host1 folder A. If you also need to destroy
64 | host2 folders that are not in host1 then use --delete2folders. See also
65 | --delete2foldersonly and --delete2foldersbutnot.
66 |
67 | Imapsync is not adequate for maintaining two active imap accounts in
68 | synchronization when the user plays independently on both sides. Use
69 | offlineimap (written by John Goerzen) or mbsync (written by Michael R.
70 | Elkins) for a 2 ways synchronization.
71 |
72 | OPTIONS
73 |
74 | usage: imapsync [options]
75 |
76 | Mandatory options are the six values, three on each sides, needed to log
77 | in into the IMAP servers, ie, a host, a username, and a password, two
78 | times.
79 |
80 | Conventions used:
81 |
82 | str means string
83 | int means integer
84 | reg means regular expression
85 | cmd means command
86 |
87 | --dry : Makes imapsync doing nothing for real, just print what
88 | would be done without --dry.
89 |
90 | OPTIONS/credentials
91 |
92 | --host1 str : Source or "from" imap server. Mandatory.
93 | --port1 int : Port to connect on host1.
94 | Optional since default port is 143 or 993 if --ssl1
95 | --user1 str : User to login on host1. Mandatory.
96 | --password1 str : Password for the user1.
97 |
98 | --host2 str : "destination" imap server. Mandatory.
99 | --port2 int : Port to connect on host2.
100 | Optional since default port is 143 or 993 if --ssl2
101 | --user2 str : User to login on host2. Mandatory.
102 | --password2 str : Password for the user2.
103 |
104 | --showpasswords : Shows passwords on output instead of "MASKED".
105 | Useful to restart a complete run by just reading the log,
106 | or to debug passwords. It's not a secure practice.
107 |
108 | --passfile1 str : Password file for the user1. It must contain the
109 | password on the first line. This option avoids to show
110 | the password on the command line like --password1 does.
111 | --passfile2 str : Password file for the user2. Contains the password.
112 |
113 | OPTIONS/encryption
114 |
115 | --nossl1 : Do not use a SSL connection on host1.
116 | --ssl1 : Use a SSL connection on host1. On by default if possible.
117 |
118 | --nossl2 : Do not use a SSL connection on host2.
119 | --ssl2 : Use a SSL connection on host2. On by default if possible.
120 |
121 | --notls1 : Do not use a TLS connection on host1.
122 | --tls1 : Use a TLS connection on host1. On by default if possible.
123 |
124 | --notls2 : Do not use a TLS connection on host2.
125 | --tls2 : Use a TLS connection on host2. On by default if possible.
126 |
127 | --debugssl int : SSL debug mode from 0 to 4.
128 |
129 | --sslargs1 str : Pass any ssl parameter for host1 ssl or tls connection. Example:
130 | --sslargs1 SSL_verify_mode=1 --sslargs1 SSL_version=SSLv3
131 | See all possibilities in the new() method of IO::Socket::SSL
132 | http://search.cpan.org/perldoc?IO::Socket::SSL#Description_Of_Methods
133 | --sslargs2 str : Pass any ssl parameter for host2 ssl or tls connection.
134 | See --sslargs1
135 |
136 | --timeout1 int : Connection timeout in seconds for host1.
137 | Default is 120 and 0 means no timeout at all.
138 | --timeout2 int : Connection timeout in seconds for host2.
139 | Default is 120 and 0 means no timeout at all.
140 |
141 | OPTIONS/authentication
142 |
143 | --authmech1 str : Auth mechanism to use with host1:
144 | PLAIN, LOGIN, CRAM-MD5 etc. Use UPPERCASE.
145 | --authmech2 str : Auth mechanism to use with host2. See --authmech1
146 |
147 | --authuser1 str : User to auth with on host1 (admin user).
148 | Avoid using --authmech1 SOMETHING with --authuser1.
149 | --authuser2 str : User to auth with on host2 (admin user).
150 | --proxyauth1 : Use proxyauth on host1. Requires --authuser1.
151 | Required by Sun/iPlanet/Netscape IMAP servers to
152 | be able to use an administrative user.
153 | --proxyauth2 : Use proxyauth on host2. Requires --authuser2.
154 |
155 | --authmd51 : Use MD5 authentication for host1.
156 | --authmd52 : Use MD5 authentication for host2.
157 | --domain1 str : Domain on host1 (NTLM authentication).
158 | --domain2 str : Domain on host2 (NTLM authentication).
159 |
160 | OPTIONS/folders
161 |
162 | --folder str : Sync this folder.
163 | --folder str : and this one, etc.
164 | --folderrec str : Sync this folder recursively.
165 | --folderrec str : and this one, etc.
166 |
167 | --folderfirst str : Sync this folder first. --folderfirst "Work"
168 | --folderfirst str : then this one, etc.
169 | --folderlast str : Sync this folder last. --folderlast "[Gmail]/All Mail"
170 | --folderlast str : then this one, etc.
171 |
172 | --nomixfolders : Do not merge folders when host1 is case-sensitive
173 | while host2 is not (like Exchange). Only the first
174 | similar folder is synced (ex: with Sent SENT sent
175 | on host1 only Sent will be synced to host2).
176 |
177 | --skipemptyfolders : Empty host1 folders are not created on host2.
178 |
179 | --include reg : Sync folders matching this regular expression
180 | --include reg : or this one, etc.
181 | If both --include --exclude options are used, then
182 | include is done before.
183 | --exclude reg : Skips folders matching this regular expression
184 | Several folders to avoid:
185 | --exclude 'fold1|fold2|f3' skips fold1, fold2 and f3.
186 | --exclude reg : or this one, etc.
187 |
188 | --automap : guesses folders mapping, for folders well known as
189 | "Sent", "Junk", "Drafts", "All", "Archive", "Flagged".
190 |
191 | --f1f2 str1=str2 : Force folder str1 to be synced to str2,
192 | --f1f2 overrides --automap and --regextrans2.
193 |
194 | --subfolder2 str : Move whole host1 folders hierarchy under this
195 | host2 folder str .
196 | It does it by adding two --regextrans2 options before
197 | all others. Add --debug to see what's really going on.
198 |
199 | --subscribed : Transfers subscribed folders.
200 | --subscribe : Subscribe to the folders transferred on the
201 | host2 that are subscribed on host1. On by default.
202 | --subscribeall : Subscribe to the folders transferred on the
203 | host2 even if they are not subscribed on host1.
204 |
205 | --prefix1 str : Remove prefix str to all destination folders,
206 | usually INBOX. or INBOX/ or an empty string "".
207 | imapsync guesses the prefix if host1 imap server
208 | does not have NAMESPACE capability. This option
209 | should not be used, most of the time.
210 | --prefix2 str : Add prefix to all host2 folders. See --prefix1
211 | --sep1 str : Host1 separator in case NAMESPACE is not supported.
212 | --sep2 str : Host2 separator in case NAMESPACE is not supported.
213 |
214 | --regextrans2 reg : Apply the whole regex to each destination folders.
215 | --regextrans2 reg : and this one. etc.
216 | When you play with the --regextrans2 option, first
217 | add also the safe options --dry --justfolders
218 | Then, when happy, remove --dry, remove --justfolders.
219 | Have in mind that --regextrans2 is applied after prefix
220 | and separator inversion. For examples see
221 | https://imapsync.lamiral.info/FAQ.d/FAQ.Folders_Mapping.txt
222 |
223 | OPTIONS/folders sizes
224 |
225 | --nofoldersizes : Do not calculate the size of each folder at the
226 | beginning of the sync. Default is to calculate them.
227 | --nofoldersizesatend: Do not calculate the size of each folder at the
228 | end of the sync. Default is to calculate them.
229 | --justfoldersizes : Exit after having printed the initial folder sizes.
230 |
231 | OPTIONS/tmp
232 |
233 | --tmpdir str : Where to store temporary files and subdirectories.
234 | Will be created if it doesn't exist.
235 | Default is system specific, Unix is /tmp but
236 | /tmp is often too small and deleted at reboot.
237 | --tmpdir /var/tmp should be better.
238 | --pidfile str : The file where imapsync pid is written,
239 | it can be dirname/filename.
240 | Default name is imapsync.pid in tmpdir.
241 | --pidfilelocking : Abort if pidfile already exists. Useful to avoid
242 | concurrent transfers on the same mailbox.
243 |
244 | OPTIONS/log
245 |
246 | --nolog : Turn off logging on file
247 | --logfile str : Change the default log filename (can be dirname/filename).
248 | --logdir str : Change the default log directory. Default is LOG_imapsync/
249 |
250 | OPTIONS/messages
251 |
252 | --skipmess reg : Skips messages matching the regex.
253 | Example: 'm/[\x80-ff]/' # to avoid 8bits messages.
254 | --skipmess is applied before --regexmess
255 | --skipmess reg : or this one, etc.
256 |
257 | --pipemess cmd : Apply this cmd command to each message content
258 | before the copy.
259 | --pipemess cmd : and this one, etc.
260 |
261 | --disarmreadreceipts : Disarms read receipts (host2 Exchange issue)
262 |
263 | --regexmess reg : Apply the whole regex to each message before transfer.
264 | Example: 's/\000/ /g' # to replace null by space.
265 | --regexmess reg : and this one, etc.
266 |
267 | OPTIONS/flags
268 |
269 | --regexflag reg : Apply the whole regex to each flags list.
270 | Example: 's/"Junk"//g' # to remove "Junk" flag.
271 | --regexflag reg : then this one, etc.
272 |
273 | --resyncflags : Resync flags for already transferred messages.
274 | On by default.
275 | --noresyncflags : Do not resync flags for already transferred messages.
276 | May be useful when a user has already started to play
277 | with its host2 account.
278 |
279 | OPTIONS/deletions
280 |
281 | --delete1 : Deletes messages on host1 server after a successful
282 | transfer. Option --delete1 has the following behavior:
283 | it marks messages as deleted with the IMAP flag
284 | \Deleted, then messages are really deleted with an
285 | EXPUNGE IMAP command. If expunging after each message
286 | slows down too much the sync then use
287 | --noexpungeaftereach to speed up.
288 | --expunge1 : Expunge messages on host1 just before syncing a folder.
289 | Expunge is done per folder.
290 | Expunge aims is to really delete messages marked deleted.
291 | An expunge is also done after each message copied
292 | if option --delete1 is set.
293 | --noexpunge1 : Do not expunge messages on host1.
294 | --delete1emptyfolders : Deletes empty folders on host1, INBOX excepted.
295 | Useful with --delete1 since what remains on host1
296 | is only what failed to be synced.
297 |
298 | --delete2 : Delete messages in host2 that are not in
299 | host1 server. Useful for backup or pre-sync.
300 | --delete2duplicates : Delete messages in host2 that are duplicates.
301 | Works only without --useuid since duplicates are
302 | detected with an header part of each message.
303 |
304 | --delete2folders : Delete folders in host2 that are not in host1 server.
305 | For safety, first try it like this (it is safe):
306 | --delete2folders --dry --justfolders --nofoldersizes
307 | --delete2foldersonly reg : Deleted only folders matching regex.
308 | Example: --delete2foldersonly "/^Junk$|^INBOX.Junk$/"
309 | --delete2foldersbutnot reg : Do not delete folders matching regex.
310 | Example: --delete2foldersbutnot "/Tasks$|Contacts$|Foo$/"
311 |
312 | --expunge2 : Expunge messages on host2 after messages transfer.
313 | --uidexpunge2 : uidexpunge messages on the host2 account
314 | that are not on the host1 account, requires --delete2
315 |
316 | OPTIONS/dates
317 |
318 | --syncinternaldates : Sets the internal dates on host2 same as host1.
319 | Turned on by default. Internal date is the date
320 | a message arrived on a host (mtime).
321 | --idatefromheader : Sets the internal dates on host2 same as the
322 | "Date:" headers.
323 | If you encounter problems with dates see also
324 | https://imapsync.lamiral.info/FAQ.d/FAQ.Dates.txt
325 |
326 | OPTIONS/message selection
327 |
328 | --maxsize int : Skip messages larger (or equal) than int bytes
329 | --minsize int : Skip messages smaller (or equal) than int bytes
330 | --maxage int : Skip messages older than int days.
331 | final stats (skipped) don't count older messages
332 | see also --minage
333 | --minage int : Skip messages newer than int days.
334 | final stats (skipped) don't count newer messages
335 | You can do (+ are the messages selected):
336 | past|----maxage+++++++++++++++>now
337 | past|+++++++++++++++minage---->now
338 | past|----maxage+++++minage---->now (intersection)
339 | past|++++minage-----maxage++++>now (union)
340 |
341 | --search str : Selects only messages returned by this IMAP SEARCH
342 | command. Applied on both sides.
343 | For a complete of what can be search see
344 | https://imapsync.lamiral.info/FAQ.d/FAQ.Messages_Selection.txt
345 |
346 | --search1 str : Same as --search but for selecting host1 messages only.
347 | --search2 str : Same as --search but for selecting host2 messages only.
348 | --search CRIT equals --search1 CRIT --search2 CRIT
349 |
350 | --maxlinelength int : skip messages with a line length longer than int bytes.
351 | RFC 2822 says it must be no more than 1000 bytes.
352 |
353 |
354 | --useheader str : Use this header to compare messages on both sides.
355 | Ex: Message-ID or Subject or Date.
356 | --useheader str and this one, etc.
357 |
358 | --usecache : Use cache to speed up the sync.
359 | --nousecache : Do not use cache. Caveat: --useuid --nousecache creates
360 | duplicates on multiple runs.
361 | --useuid : Use UIDs instead of headers as a criterium to recognize
362 | messages. Option --usecache is then implied unless
363 | --nousecache is used.
364 |
365 | OPTIONS/miscellaneous
366 |
367 | --syncacls : Synchronizes acls (Access Control Lists).
368 | --nosyncacls : Does not synchronize acls. This is the default.
369 | Acls in IMAP are not standardized, be careful.
370 |
371 | OPTIONS/debugging
372 |
373 | --debug : Debug mode.
374 | --debugfolders : Debug mode for the folders part only.
375 | --debugcontent : Debug content of the messages transferred. Huge output.
376 | --debugflags : Debug mode for flags.
377 | --debugimap1 : IMAP debug mode for host1. Very verbose.
378 | --debugimap2 : IMAP debug mode for host2. Very verbose.
379 | --debugimap : IMAP debug mode for host1 and host2. Twice very verbose.
380 | --debugmemory : Debug mode showing memory consumption after each copy.
381 |
382 | --errorsmax int : Exit when int number of errors is reached. Default is 50.
383 |
384 | --tests : Run local non-regression tests. Exit code 0 means all ok.
385 | --testslive : Run a live test with test1.lamiral.info imap server.
386 | Useful to check the basics. Needs internet connection.
387 | --testslive6 : Run a live test with ks2ipv6.lamiral.info imap server.
388 | Useful to check the ipv6 connectivity. Needs internet.
389 |
390 | OPTIONS/specific
391 |
392 | --gmail1 : sets --host1 to Gmail and options from FAQ.Gmail.txt
393 | --gmail2 : sets --host2 to Gmail and options from FAQ.Gmail.txt
394 |
395 | --office1 : sets --host1 to Office365 options from FAQ.Exchange.txt
396 | --office2 : sets --host2 to Office365 options from FAQ.Exchange.txt
397 |
398 | --exchange1 : sets options from FAQ.Exchange.txt, account1 part
399 | --exchange2 : sets options from FAQ.Exchange.txt, account2 part
400 |
401 | --domino1 : sets options from FAQ.Domino.txt, account1 part
402 | --domino2 : sets options from FAQ.Domino.txt, account2 part
403 |
404 | OPTIONS/behavior
405 |
406 | --maxmessagespersecond int : limits the number of messages transferred per second.
407 |
408 | --maxbytespersecond int : limits the average transfer rate per second.
409 | --maxbytesafter int : starts --maxbytespersecond limitation only after
410 | --maxbytesafter amount of data transferred.
411 |
412 | --maxsleep int : do not sleep more than int seconds.
413 | On by default, 2 seconds max, like --maxsleep 2
414 |
415 | --abort : terminates a previous call still running.
416 | It uses the pidfile to know what process to abort.
417 |
418 | --exitwhenover int : Stop syncing when total bytes transferred reached.
419 |
420 | --version : Print only software version.
421 | --noreleasecheck : Do not check for new imapsync release (a http request).
422 | --releasecheck : Check for new imapsync release (a http request).
423 | --noid : Do not send/receive ID command to imap servers.
424 | --justconnect : Just connect to both servers and print useful
425 | information. Need only --host1 and --host2 options.
426 | --justlogin : Just login to both host1 and host2 with users
427 | credentials, then exit.
428 | --justfolders : Do only things about folders (ignore messages).
429 |
430 | --help : print this help.
431 |
432 | Example: to synchronize imap account "test1" on "test1.lamiral.info"
433 | to imap account "test2" on "test2.lamiral.info"
434 | with test1 password "secret1"
435 | and test2 password "secret2"
436 |
437 | imapsync \
438 | --host1 test1.lamiral.info --user1 test1 --password1 secret1 \
439 | --host2 test2.lamiral.info --user2 test2 --password2 secret2
440 |
441 | SECURITY
442 |
443 | You can use --passfile1 instead of --password1 to give the password
444 | since it is safer. With --password1 option, any user on your host can
445 | see the password by using the 'ps auxwwww' command. Using a variable
446 | (like $PASSWORD1) is also dangerous because of the 'ps auxwwwwe'
447 | command. So, saving the password in a well protected file (600 or
448 | rw-------) is the best solution.
449 |
450 | Imapsync activates ssl or tls encryption by default, if possible. What
451 | detailed behavior is under this "if possible"? Imapsync activates ssl if
452 | the well known port imaps port (993) is open on the imap servers. If the
453 | imaps port is closed then it open a normal (clear) connection on port
454 | 143 but it looks for TLS support in the CAPABILITY list of the servers.
455 | If TLS is supported then imapsync goes to encryption.
456 |
457 | If the automatic ssl/tls detection fails then imapsync will not protect
458 | against sniffing activities on the network, especially for passwords.
459 |
460 | If you want to force ssl or tls just use --ssl1 --ssl2 or --tls1 --tls2
461 |
462 | See also the document FAQ.Security.txt in the FAQ.d/ directory or at
463 | https://imapsync.lamiral.info/FAQ.d/FAQ.Security.txt
464 |
465 | EXIT STATUS
466 |
467 | Imapsync will exit with a 0 status (return code) if everything went
468 | good. Otherwise, it exits with a non-zero status.
469 |
470 | LICENSE AND COPYRIGHT
471 |
472 | Imapsync is free, open, public but not always gratis software cover by
473 | the NOLIMIT Public License. See the LICENSE file included in the
474 | distribution or just read this simple sentence as it IS the licence
475 | text:
476 |
477 | "No limits to do anything with this work and this license."
478 |
479 | In case it is not long enough, I repeat:
480 |
481 | "No limits to do anything with this work and this license."
482 |
483 | https://imapsync.lamiral.info/LICENSE
484 |
485 | AUTHOR
486 |
487 | Gilles LAMIRAL
488 |
489 | Feedback good or bad is very often welcome.
490 |
491 | Gilles LAMIRAL earns his living by writing, installing, configuring and
492 | teaching free, open and often gratis software. Imapsync used to be
493 | "always gratis" but now it is only "often gratis" because imapsync is
494 | sold by its author, a good way to maintain and support free open public
495 | software over decades.
496 |
497 | BUGS AND LIMITATIONS
498 |
499 | See https://imapsync.lamiral.info/FAQ.d/FAQ.Reporting_Bugs.txt
500 |
501 | IMAP SERVERS supported
502 |
503 | See https://imapsync.lamiral.info/S/imapservers.shtml
504 |
505 | HUGE MIGRATION
506 |
507 | Pay special attention to options --subscribed --subscribe --delete1
508 | --delete1emptyfolders --delete2 --delete2folders --maxage --minage
509 | --maxsize --useuid --usecache
510 |
511 | If you have many mailboxes to migrate think about a little shell
512 | program. Write a file called file.txt (for example) containing users and
513 | passwords. The separator used in this example is ';'
514 |
515 | The file.txt file contains:
516 |
517 | user001_1;password001_1;user001_2;password001_2
518 | user002_1;password002_1;user002_2;password002_2
519 | user003_1;password003_1;user003_2;password003_2
520 | user004_1;password004_1;user004_2;password004_2
521 | user005_1;password005_1;user005_2;password005_2 ...
522 |
523 | On Unix the shell program can be:
524 |
525 | { while IFS=';' read u1 p1 u2 p2; do
526 | imapsync --host1 imap.side1.org --user1 "$u1" --password1 "$p1" \
527 | --host2 imap.side2.org --user2 "$u2" --password2 "$p2" ...
528 | done ; } < file.txt
529 |
530 | On Windows the batch program can be:
531 |
532 | FOR /F "tokens=1,2,3,4 delims=; eol=#" %%G IN (file.txt) DO imapsync ^
533 | --host1 imap.side1.org --user1 %%G --password1 %%H ^
534 | --host2 imap.side2.org --user2 %%I --password2 %%J ...
535 |
536 | The ... have to be replaced by nothing or any imapsync option. Welcome
537 | in shell or batch programming !
538 |
539 | You will find already written scripts at
540 | https://imapsync.lamiral.info/examples/
541 |
542 | INSTALL
543 |
544 | Imapsync works under any Unix with perl.
545 |
546 | Imapsync works under most Windows (2000, XP, Vista, Seven, Eight, Ten
547 | and all Server releases 2000, 2003, 2008 and R2, 2012 and R2)
548 | as a standalone binary software called imapsync.exe,
549 | usually launched from a batch file in order to avoid always typing
550 | the options.
551 |
552 | Imapsync works under OS X as a standalone binary
553 | software called imapsync_bin_Darwin
554 |
555 | Purchase latest imapsync at
556 | https://imapsync.lamiral.info/
557 |
558 | You'll receive a link to a compressed tarball called imapsync-x.xx.tgz
559 | where x.xx is the version number. Untar the tarball where
560 | you want (on Unix):
561 |
562 | tar xzvf imapsync-x.xx.tgz
563 |
564 | Go into the directory imapsync-x.xx and read the INSTALL file.
565 | As mentioned at https://imapsync.lamiral.info/#install
566 | the INSTALL file can also be found at
567 | https://imapsync.lamiral.info/INSTALL.d/INSTALL.ANY.txt
568 | It is now split in several files for each system
569 | https://imapsync.lamiral.info/INSTALL.d/
570 |
571 | CONFIGURATION
572 |
573 | There is no specific configuration file for imapsync, everything is
574 | specified by the command line parameters and the default behavior.
575 |
576 | HACKING
577 |
578 | Feel free to hack imapsync as the NOLIMIT license permits it.
579 |
580 | SIMILAR SOFTWARE
581 |
582 | See also https://imapsync.lamiral.info/S/external.shtml
583 | for a better up to date list.
584 |
585 | imap_tools : https://github.com/andrewnimmo/rick-sanders-imap-tools
586 | offlineimap : https://github.com/nicolas33/offlineimap
587 | Doveadm-Sync : http://wiki2.dovecot.org/Tools/Doveadm/Sync
588 | ( Dovecot sync tool )
589 | mbsync : http://isync.sourceforge.net/
590 | mailsync : http://mailsync.sourceforge.net/
591 | mailutil : http://www.washington.edu/imap/
592 | part of the UW IMAP tookit.
593 | imaprepl : http://www.bl0rg.net/software/
594 | http://freecode.com/projects/imap-repl/
595 | imapcopy : http://www.ardiehl.de/imapcopy/
596 | migrationtool : http://sourceforge.net/projects/migrationtool/
597 | imapmigrate : http://sourceforge.net/projects/cyrus-utils/
598 | wonko_imapsync: http://wonko.com/article/554
599 | see also file W/tools/wonko_ruby_imapsync
600 | exchange-away : http://exchange-away.sourceforge.net/
601 | pop2imap : http://www.linux-france.org/prj/pop2imap/
602 |
603 | Feedback (good or bad) will often be welcome.
604 |
605 | HISTORY
606 |
607 | I wrote imapsync because an enterprise (basystemes) paid me to install a
608 | new imap server without losing huge old mailboxes located in a far away
609 | remote imap server, accessible by a low-bandwidth often broken link. The
610 | tool imapcp (written in python) could not help me because I had to
611 | verify every mailbox was well transferred, and then delete it after a
612 | good transfer. Imapsync started its life as a patch of the
613 | copy_folder.pl script. The script copy_folder.pl comes from the
614 | Mail-IMAPClient-2.1.3 perl module tarball source (more precisely in the
615 | examples/ directory of the Mail-IMAPClient tarball). So many happened
616 | since then that I wonder if it remains any lines of the original
617 | copy_folder.pl in imapsync source code.
618 |
619 |
--------------------------------------------------------------------------------
/imapsync_binaries/windows/README_Windows.txt:
--------------------------------------------------------------------------------
1 | # $Id: README_Windows.txt,v 1.11 2018/05/05 22:46:01 gilles Exp gilles $
2 | #
3 | # This is the README_Windows.txt file for imapsync
4 | # imapsync : IMAP sync and migrate tool.
5 |
6 | WINDOWS
7 | =======
8 |
9 | There is two ways to install and use imapsync on Windows systems: A) or B).
10 |
11 | Standard users should take the A) way, the simplest way.
12 |
13 | Developers, or powerful users that want to build their own imapsync.exe
14 | or modify it, have to consider the B) way, the complex but powerful way.
15 |
16 | A) Simplest way
17 | ---------------
18 |
19 | A.1) Get imapsync.
20 |
21 | Get imapsync at https://imapsync.lamiral.info/
22 | You'll then have access to a zip archive file named imapsync_1.xxx.zip
23 | where 1.xxx is the imapsync release number.
24 |
25 | A.2) Extract the zip file in a folder where you will work with imapsync.
26 |
27 | You can work on the Desktop since the zip file extraction creates
28 | a unique folder named imapsync_1.xxx (where 1.xxx is the imapsync
29 | release number).
30 |
31 | A.3) Check the folder
32 |
33 | In the folder extracted imapsync_1.xxx you see 6 files and 2 directories:
34 |
35 | * README_Windows.txt is the current file you are reading.
36 | * README.txt is the imapsync general document.
37 | * FAQ.d/* FAQs are a good read when something goes wrong.
38 | * imapsync_example.bat is a simple batch file example you will copy and edit.
39 | * sync_loop_windows.bat is a batch file example for syncing many accounts.
40 | * file.txt is an input file example for syncing many accounts.
41 | * imapsync.exe is the imapsync binary. You don't have to run it directly.
42 | * Cook/ is the directory to build imapsync.exe from its source,
43 | for the B) way and expert users.
44 |
45 | You can copy or rename imapsync_example.bat as you wish as long as
46 | its extension remains ".bat". On Windows systems .bat extension
47 | means "I'm a batch script". Same thing for sync_loop_windows.bat.
48 | The batch scripts have to stay in the same directory than
49 | imapsync.exe because of the way they call imapsync.exe,
50 | they use ".\imapsync.exe", so let them be in the same directory.
51 | Or change the path .\ to whatever you want if you understand what
52 | you're doing.
53 |
54 | For the rest of this documentation I assume you copied
55 | imapsync_example.bat to a file named imapsync_stuff.bat
56 |
57 | A.4) Edit the batch file
58 |
59 | Edit imapsync_stuff.bat and change the values with yours.
60 | In order to edit it you have do a right click on it and select "modify"
61 | in the list presented in the small window menu.
62 | Notepad or Notepadd++ are very good editors to modify it.
63 | Office Word or any powerful text processor are not good for that job,
64 | don't use them!
65 |
66 | Files FAQ.txt and FAQ.d/* contain many tips and special options sometimes
67 | needed by specific imap server softwares like Exchange or Gmail.
68 |
69 |
70 | A.5) Run the batch file
71 |
72 | To run imapsync with your values just double-click on
73 | the batch file imapsync_stuff.bat
74 |
75 | You do not need to have administrator privileges to run imapsync.
76 |
77 | A.6) Loop on A.5) A.6) edit, run, edit, run etc.
78 |
79 | Loop the process of editing and running imapsync until
80 | you solve all issues and all values suit your needs.
81 |
82 | A.7) Look the sync running. You can abort it at any time with a
83 | quick double ctrl-c, hit ctrl-c twice within one second.
84 | (a single ctrl-c will reconnect to both imap servers)
85 |
86 | A.8) When the sync is finished you can find the whole log of the output
87 | in the folder named "LOG_imapsync", the logfile name is based
88 | on the launching date, hour, minute, second, miliseconds and the
89 | user2 parameter. There is one logfile per run.
90 | The logfile name is printed at the end of the imapsync run.
91 | If you do not want logging to a file then use option --nolog
92 |
93 |
94 | B) Hard way. It is the hard way because it installs all software
95 | dependencies. This is the way for modifying imapsync.exe if needed.
96 |
97 | B.1) Install Perl if it isn't already installed.
98 | Strawberry Perl is a very good candidate
99 | http://strawberryperl.com/
100 | I use 5.26.0.1 (31 may 2017) but previous and later releases
101 | should work (5.18 and 5.20 do) as well.
102 |
103 | B.2) Go into the Cook/ directory
104 | B.3) Double-clic build_exe.bat
105 |
106 | It should create a binary imapsync.exe in the current Cook/ directory.
107 |
108 | B.4) Move imapsync.exe in the upper directory and follow instructions
109 | from A.3) to A.8)
110 |
111 |
--------------------------------------------------------------------------------
/imapsync_binaries/windows/file.txt:
--------------------------------------------------------------------------------
1 | # Example file.txt for imapsync massive migration.
2 | #
3 | # $Id: file.txt,v 1.14 2018/02/11 13:42:58 gilles Exp gilles $
4 | #
5 | # Each line contains 6 columns, columns are parameters for
6 | # --host1 --user1 --password1 --host2 --user2 --password2
7 | # and a trailing empty fake column to avoid CR LF part going
8 | # in the 6th parameter password2. Don't forget the last semicolon.
9 | #
10 | # Windows: see the script examples/sync_loop_windows.bat
11 | # Unix: see the script examples/sync_loop_unix.sh
12 | #
13 | # Lines starting with a # are comments and ignored
14 | # Blank lines are ignored as well
15 |
16 |
17 | # Now the data example
18 | host001_1;user001_1;password001_1;host001_2;user001_2;password001_2;
19 | host002_1;user002_1;password002_1;host002_2;user002_2;password002_2;
20 | host003_1;user003_1;password003_1;host003_2;user003_2;password003_2;
21 |
22 | # Another comment blabla
23 | host004_1;user004_1;password004_1;host004_2;user004_2;password004_2;
24 |
25 | # This last example is a real one, ie, truly working in the real world.
26 | test1.lamiral.info;test1;secret1;test2.lamiral.info;test2;secret2;
27 |
--------------------------------------------------------------------------------
/imapsync_binaries/windows/imapsync.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/imapsync_binaries/windows/imapsync.exe
--------------------------------------------------------------------------------
/imapsync_binaries/windows/imapsync_example.bat:
--------------------------------------------------------------------------------
1 | @REM $Id: imapsync_example.bat,v 1.10 2016/04/07 23:14:09 gilles Exp gilles $
2 |
3 | @REM imapsync example batch for Windows users
4 | @REM lines beginning with @REM are just comments
5 |
6 | @REM See http://imapsync.lamiral.info/#doc
7 | @REM for more details on how to use imapsync.
8 |
9 | @REM Replace below the 6 parameters
10 | @REM "test1.lamiral.info" "test1" "secret1" "test2.lamiral.info" "test2" "secret2"
11 | @REM with your own values
12 | @REM Double quotes are necessary if a value contain one or more blanks.
13 |
14 | @REM value "test1.lamiral.info" for --host1 is the IMAP source server hostname or IP address
15 | @REM value "test1" for --user1 is the IMAP source user login
16 | @REM value "secret1" for --password1 is the IMAP source user password
17 |
18 | @REM value "test2.lamiral.info" for --host2 is the IMAP destination server hostname or IP address
19 | @REM value "test2" for --user2 is the IMAP destination user login
20 | @REM value "secret2" for --password2 is the IMAP destination user password
21 |
22 | @REM Character ^ at the end of the first line is essential and means
23 | @REM "this command continues on the next line". You can add other lines
24 | @REM but don't forget ^ character lasting each line, except the last one.
25 |
26 |
27 | @REM Three other options are in this example because they are good to start with
28 | @REM
29 | @REM --dry makes imapsync doing nothing, just print what would be done without --dry.
30 | @REM
31 | @REM --justfolders does only things about folders (ignore messages). It is good
32 | @REM to verify the folder mapping is good for you.
33 | @REM
34 | @REM --automap guesses folders mapping, for folders like
35 | @REM "Sent", "Junk", "Drafts", "All", "Archive", "Flagged".
36 | @REM
37 | @REM I suggest to start with --automap --justfolders --dry.
38 | @REM If the folder mapping is not good then add some --f1f2 folder1=folder2
39 | @REM to fix it.
40 | @REM Then remove --dry and have a run to create folders on host2.
41 | @REM If everything goes well so far then remove --justfolders to
42 | @REM start syncing messages.
43 |
44 | .\imapsync.exe --host1 test1.lamiral.info --user1 test1 --password1 "secret1" ^
45 | --host2 test2.lamiral.info --user2 test2 --password2 "secret2" ^
46 | --automap --justfolders --dry
47 |
48 |
49 | @PAUSE
50 |
51 |
--------------------------------------------------------------------------------
/imapsync_binaries/windows/sync_loop_windows.bat:
--------------------------------------------------------------------------------
1 | @REM
2 | @REM $Id: sync_loop_windows.bat,v 1.18 2018/05/24 11:45:42 gilles Exp gilles $
3 | @REM
4 | @REM imapsync massive sync example batch for Windows users
5 | @REM lines beginning with @REM are just comments
6 | @REM
7 | @REM See also http://imapsync.lamiral.info/FAQ.d/FAQ.Massive.txt
8 | @REM
9 | @REM You should get familiar with a simple and single imapsync transfer before
10 | @REM playing with this loop batch file. See and play with imapsync_example.bat
11 |
12 | @REM ==== How it works ====
13 | @REM
14 | @REM The files
15 | @REM * sync_loop_windows.bat
16 | @REM * imapsync or imapsync.exe and
17 | @REM * file.txt
18 | @REM are supposed to be in the same directory.
19 |
20 |
21 | @REM ==== Credentials file ====
22 | @REM
23 | @REM Credentials data are supposed to be in the file named "file.txt" in the following format:
24 | @REM host001_1;user001_1;password001_1;host001_2;user001_2;password001_2;
25 | @REM ...
26 | @REM Separator is character semi-colon ; it can be replaced with any character by changing
27 | @REM the part "delims=;" in the FOR loop below.
28 | @REM
29 | @REM Each data line contains 6 columns, columns are parameter values for
30 | @REM --host1 --user1 --password1 --host2 --user2 --password2
31 | @REM and a fake parameter to avoid CRLF part going into the 6th parameter password2.
32 | @REM The credentials filename "file.txt" used for the loop can be renamed
33 | @REM by changing "SET csvfile=file.txt" below.
34 |
35 | @REM ==== Log files ====
36 | @REM
37 | @REM Log files are in the LOG_imapsync sub-folder
38 |
39 | @REM ==== Parallel executions ====
40 | @REM
41 | @REM If you want to do parallel runs of imapsync then this current script is a good start.
42 | @REM Just copy it several times and replace, on each copy, the csvfile variable value.
43 | @REM Instead of SET csvfile=file.txt write for example
44 | @REM SET csvfile=file01.txt in the first copy
45 | @REM then also
46 | @REM SET csvfile=file02.txt in the second copy etc.
47 | @REM Of course you also have to split data contained in file.txt
48 | @REM into file01.txt file02.txt etc.
49 | @REM After that, just double-clic on each batch file to launch each process
50 | @REM
51 | @REM Be aware that imapsync can be a cpu/memory cruncher on the remote imap servers,
52 | @REM especially in parallel runs. The best practice rule to answer the question
53 | @REM "how many processes in parallel can we run?" is:
54 | @REM 1) Measure the total transfer rate by adding each one printed in each run.
55 | @REM 2) Launch new parallel runs as long as the total transfer rate increase.
56 | @REM 3) When the total transfer rate starts to diminish, stop new launches.
57 | @REM Note N as the number of parallel runs you got until then.
58 | @REM 4) Only keep N-2 parallel runs for the future.
59 |
60 | @REM For Parallel executions, there is also a PowerShell script written by
61 | @REM CARTER Alex explained and located on the imapsync archive list:
62 | @REM http://www.linux-france.org/prj/imapsync_list/msg02137.html
63 |
64 | @REM ==== The real stuff is below ====
65 |
66 | @REM @echo off
67 |
68 | @REM First let's go in the directory this batch is
69 | CD /D %~dp0
70 |
71 | @REM Let's get arguments of this batch, they will be added to imapsync arguments, if any.
72 | @REM Do not touch this part to add arguments to imapsync, do that in the FOR loop below
73 | @SET arguments= & @SET command=%~0
74 | @IF %1. EQU . GOTO args_end
75 | :args_loop
76 | @SET arguments=%arguments% %1 & @SHIFT
77 | @IF %1. NEQ . GOTO args_loop
78 | @ECHO Command and arguments: %command% %arguments%
79 | :args_end
80 |
81 | @REM Now the loop on the csv file.
82 | SET csvfile=file.txt
83 |
84 | @FOR /F "tokens=1,2,3,4,5,6,7 delims=; eol=#" %%G IN (%csvfile%) DO (
85 | @REM Blank lines are usually ignored. Dumping the tokens in [] in case debugging is needed
86 | @ECHO GOT those values from %csvfile% presented inside brackets: [%%G] [%%H] [%%I] [%%J] [%%K] [%%L] [%%M]
87 | @REM You can add extra arguments to imapsync after the variable named %arguments%
88 | @ECHO ==== Starting imapsync from --host1 %%G --user1 %%H to --host2 %%J --user2 %%K ====
89 | @imapsync ^
90 | --host1 %%G --user1 %%H --password1 %%I ^
91 | --host2 %%J --user2 %%K --password2 %%L %%M %arguments%
92 | @ECHO ==== Ended imapsync from --host1 %%G --user1 %%H to --host2 %%J --user2 %%K ====
93 | @ECHO.
94 | )
95 |
96 | @ECHO Loop finished!
97 | @ECHO Log files are in LOG_imapsync directory
98 | @PAUSE
99 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "imapsyncclient",
3 | "displayName": "ImapSync Client",
4 | "productName": "ImapSync Client",
5 | "homepage": "https://github.com/ridaamirini/ImapSyncClient",
6 | "version": "1.0.1",
7 | "author": "Rida A. ",
8 | "description": "It's only an Internet Message Access Protocol Synchronization Client",
9 | "license": "MIT",
10 | "main": "./dist/electron/main.js",
11 | "scripts": {
12 | "revision": "node .electron-vue/revision.js",
13 | "release": "node .electron-vue/build.js && electron-builder",
14 | "build": "CSC_IDENTITY_AUTO_DISCOVERY=false node .electron-vue/build.js && electron-builder",
15 | "build:dir": "node .electron-vue/build.js && electron-builder --dir",
16 | "build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js",
17 | "build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js",
18 | "dev": "node .electron-vue/dev-runner.js",
19 | "lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src",
20 | "lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src",
21 | "pack": "npm run pack:main && npm run pack:renderer",
22 | "pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js",
23 | "pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js",
24 | "postinstall": "npm run lint:fix",
25 | "impasync:upgrade:binaries": "node .imapsync/upgrade.js"
26 | },
27 | "build": {
28 | "productName": "ImapSync Client",
29 | "appId": "de.ridasmartapps.imapsyncclient",
30 | "directories": {
31 | "output": "build"
32 | },
33 | "files": [
34 | "dist/electron/**/*",
35 | "package.json",
36 | "revision.json"
37 | ],
38 | "extraResources": [
39 | {
40 | "from": "imapsync_binaries/",
41 | "to": "imapsync_binaries/",
42 | "filter": [
43 | "**/*"
44 | ]
45 | }
46 | ],
47 | "dmg": {
48 | "contents": [
49 | {
50 | "x": 410,
51 | "y": 150,
52 | "type": "link",
53 | "path": "/Applications"
54 | },
55 | {
56 | "x": 130,
57 | "y": 150,
58 | "type": "file"
59 | }
60 | ]
61 | },
62 | "mac": {
63 | "icon": "build/icons/icon.icns"
64 | },
65 | "win": {
66 | "icon": "build/icons/icon.ico",
67 | "target": [
68 | {
69 | "target": "nsis",
70 | "arch": [
71 | "x64",
72 | "ia32"
73 | ]
74 | }
75 | ]
76 | },
77 | "linux": {
78 | "icon": "build/icons",
79 | "executableName": "imapsyncclient",
80 | "synopsis": "ImapSync Client",
81 | "category": "Development",
82 | "target": [
83 | "AppImage",
84 | "deb"
85 | ]
86 | }
87 | },
88 | "dependencies": {
89 | "axios": "^0.18.1",
90 | "electron-is": "^3.0.0",
91 | "electron-log": "^1.3.0",
92 | "electron-updater": "^4.0.0",
93 | "element-ui": "^2.0.5",
94 | "git-rev-sync": "^1.9.1",
95 | "vue": "^2.3.3",
96 | "vue-electron": "^1.0.6",
97 | "vue-router": "^2.5.3",
98 | "vuex": "^2.3.1"
99 | },
100 | "devDependencies": {
101 | "babel-core": "^6.25.0",
102 | "babel-eslint": "^7.2.3",
103 | "babel-loader": "^7.1.1",
104 | "babel-plugin-transform-runtime": "^6.23.0",
105 | "babel-preset-env": "^1.6.0",
106 | "babel-preset-stage-0": "^6.24.1",
107 | "babel-register": "^6.24.1",
108 | "babili-webpack-plugin": "^0.1.2",
109 | "cfonts": "^1.1.3",
110 | "chalk": "^2.1.0",
111 | "copy-webpack-plugin": "^4.0.1",
112 | "cross-env": "^5.0.5",
113 | "css-loader": "^0.28.4",
114 | "del": "^3.0.0",
115 | "devtron": "^1.4.0",
116 | "electron": "^3.0.16",
117 | "electron-builder": "^22.3.2",
118 | "electron-debug": "^1.4.0",
119 | "electron-devtools-installer": "^2.2.0",
120 | "eslint": "^4.4.1",
121 | "eslint-config-standard": "^10.2.1",
122 | "eslint-friendly-formatter": "^3.0.0",
123 | "eslint-loader": "^1.9.0",
124 | "eslint-plugin-html": "^3.1.1",
125 | "eslint-plugin-import": "^2.7.0",
126 | "eslint-plugin-node": "^5.1.1",
127 | "eslint-plugin-promise": "^3.5.0",
128 | "eslint-plugin-standard": "^3.0.1",
129 | "extract-text-webpack-plugin": "^3.0.0",
130 | "file-loader": "^0.11.2",
131 | "html-webpack-plugin": "^2.30.1",
132 | "multispinner": "^0.2.1",
133 | "node-loader": "^0.6.0",
134 | "style-loader": "^0.18.2",
135 | "url-loader": "^0.5.9",
136 | "vue-html-loader": "^1.2.4",
137 | "vue-loader": "^13.0.5",
138 | "vue-style-loader": "^3.0.1",
139 | "vue-template-compiler": "^2.4.2",
140 | "webpack": "^3.5.2",
141 | "webpack-dev-server": "^2.7.1",
142 | "webpack-hot-middleware": "^2.18.2"
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/revision.json:
--------------------------------------------------------------------------------
1 | {
2 | "rev": "25bd519",
3 | "version": "1.0.1.25bd519",
4 | "date": "1/28/2020, 12:07:45 PM"
5 | }
--------------------------------------------------------------------------------
/src/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ImapSync Client
7 |
8 |
9 | <% if (htmlWebpackPlugin.options.nodeModules) { %>
10 |
11 |
14 | <% } %>
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/main/imapsync.js:
--------------------------------------------------------------------------------
1 | import is from 'electron-is';
2 | import fs from 'fs';
3 | import path from 'path';
4 | import {execFile} from 'child_process';
5 | import {remote} from 'electron';
6 |
7 | // Childprocess id
8 | let childProcess = null;
9 | const pidFilePath = path.join(remote.app.getPath('temp'), '/imapsync.pid');
10 |
11 | // Imapsync command options
12 | const commandOptions = [
13 | '--nolog',
14 | '--noreleasecheck',
15 | '--pidfile=' + pidFilePath,
16 | '--pidfilelocking'
17 | ];
18 |
19 | function getExecutablePath() {
20 | let binaryPath = null;
21 |
22 | if (is.windows()) {
23 | binaryPath = 'windows/imapsync.exe';
24 | }
25 | else if (is.macOS()) {
26 | binaryPath = 'darwin/imapsync';
27 | }
28 | else if (is.linux()) {
29 | binaryPath = 'bin/imapsync';
30 | }
31 |
32 | if (is.production()) {
33 | return path.join(process.resourcesPath, 'imapsync_binaries/', binaryPath);
34 | }
35 |
36 | return path.join(__dirname, '../../imapsync_binaries/', binaryPath);
37 | }
38 |
39 | function mapImapsyncCommandArgs(mailbox) {
40 | return [
41 | '--host1=' + mailbox.imap_from,
42 | '--user1=' + mailbox.mailbox_from,
43 | '--password1=' + mailbox.password_from,
44 | '--host2=' + mailbox.imap_to,
45 | '--user2=' + mailbox.mailbox_to,
46 | '--password2=' + mailbox.password_to
47 | ];
48 | }
49 |
50 | function imapsync(mailbox) {
51 | return new Promise((resolve, reject) => {
52 | let messages = {
53 | success: null,
54 | failure: null
55 | };
56 |
57 | childProcess = execFile(
58 | getExecutablePath(),
59 | [...mapImapsyncCommandArgs(mailbox), ...commandOptions],
60 | {encoding: 'utf8'},
61 | (error, stdout, stderr) => {
62 | messages.success = stdout;
63 | if (stderr || error) {
64 | messages.failure = stderr || stdout || error;
65 | }
66 | }
67 | );
68 |
69 | childProcess.on('close', code => {
70 | if (code !== 0 && messages.failure) {
71 | reject(messages.failure);
72 | }
73 |
74 | resolve(messages.success);
75 | });
76 | });
77 | }
78 |
79 | function abortImapsync() {
80 | childProcess.kill('SIGINT');
81 |
82 | if (fs.existsSync(pidFilePath)) {
83 | fs.unlink(pidFilePath, error => {
84 | if (error) console.error(error);
85 | });
86 | }
87 | }
88 |
89 | export {
90 | abortImapsync,
91 | imapsync
92 | };
93 |
--------------------------------------------------------------------------------
/src/main/index.dev.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is used specifically and only for development. It installs
3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to
4 | * modify this file, but it can be used to extend your development
5 | * environment.
6 | */
7 |
8 | /* eslint-disable */
9 |
10 | // Set environment for development
11 | process.env.NODE_ENV = 'development'
12 |
13 | // Install `electron-debug` with `devtron`
14 | require('electron-debug')({ showDevTools: true })
15 |
16 | // Install `vue-devtools`
17 | require('electron').app.on('ready', () => {
18 | let installExtension = require('electron-devtools-installer')
19 | installExtension.default(installExtension.VUEJS_DEVTOOLS)
20 | .then(() => {})
21 | .catch(err => {
22 | console.log('Unable to install `vue-devtools`: \n', err)
23 | })
24 | })
25 |
26 | // Require `main` process to boot app
27 | require('./index')
28 |
--------------------------------------------------------------------------------
/src/main/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import { app, BrowserWindow, ipcMain } from 'electron';
4 | import { checkForUpdates } from './updater';
5 |
6 | /**
7 | * Set `__static` path to static files in production
8 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
9 | */
10 | if (process.env.NODE_ENV !== 'development') {
11 | global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\');
12 | }
13 |
14 | let mainWindow;
15 | const winURL = process.env.NODE_ENV === 'development'
16 | ? `http://localhost:9080`
17 | : `file://${__dirname}/index.html`;
18 |
19 | function createWindow () {
20 | /**
21 | * Initial window options
22 | */
23 |
24 | // Linux & Windows
25 | let options = {
26 | title: app.getName(),
27 | height: 680,
28 | width: 1050,
29 | useContentSize: true,
30 | resizable: false,
31 | fullscreen: false,
32 | backgroundColor: '#272d33',
33 | show: false
34 | };
35 |
36 | if (process.platform === 'darwin') {
37 | options = {
38 | title: app.getName(),
39 | height: 680,
40 | width: 1050,
41 | useContentSize: true,
42 | resizable: false,
43 | frame: true,
44 | titleBarStyle: 'hiddenInset',
45 | fullscreen: false,
46 | backgroundColor: '#272d33',
47 | show: false
48 | };
49 | }
50 |
51 | mainWindow = new BrowserWindow(options);
52 |
53 | mainWindow.loadURL(winURL);
54 |
55 | mainWindow.on('closed', () => {
56 | mainWindow = null;
57 | });
58 |
59 | mainWindow.once('ready-to-show', () => {
60 | mainWindow.show();
61 | });
62 | }
63 |
64 | // Single Instance
65 | const instanceToQuit = app.requestSingleInstanceLock();
66 |
67 | if (!instanceToQuit) {
68 | app.quit();
69 | } else {
70 | app.on('second-instance', () => {
71 | if (mainWindow) {
72 | if (mainWindow.isMinimized()) mainWindow.restore();
73 | mainWindow.focus();
74 | }
75 | });
76 | }
77 |
78 | app.on('window-all-closed', () => {
79 | if (process.platform !== 'darwin') {
80 | app.quit();
81 | }
82 | });
83 |
84 | app.on('activate', () => {
85 | if (mainWindow === null) {
86 | createWindow();
87 | }
88 | });
89 |
90 | app.on('ready', createWindow);
91 |
92 | ipcMain.once('check-update', checkForUpdates);
93 |
--------------------------------------------------------------------------------
/src/main/menu.js:
--------------------------------------------------------------------------------
1 | const {app, Menu} = require('electron');
2 |
3 | const template = [
4 | {
5 | role: 'help',
6 | submenu: [
7 | {
8 | label: 'Learn More',
9 | click () { require('electron').shell.openExternal('https://github.com/ridaamirini/ImapSyncClient'); }
10 | }
11 | ]
12 | }
13 | ];
14 |
15 | if (process.platform === 'darwin') {
16 | template.unshift({
17 | label: app.getName(),
18 | submenu: [
19 | {role: 'about'},
20 | {role: 'quit'}
21 | ]
22 | });
23 |
24 | // Window menu
25 | template[3].submenu = [
26 | {role: 'close'},
27 | {role: 'minimize'},
28 | {role: 'zoom'},
29 | {type: 'separator'},
30 | {role: 'front'}
31 | ];
32 | }
33 |
34 | const menu = Menu.buildFromTemplate(template);
35 | Menu.setApplicationMenu(menu);
36 |
--------------------------------------------------------------------------------
/src/main/updater.js:
--------------------------------------------------------------------------------
1 | import { autoUpdater } from 'electron-updater';
2 | import log from 'electron-log';
3 | import { app, ipcMain } from 'electron';
4 |
5 | let isAutomaticallyCheckingForUpdates = false;
6 |
7 | app.once('browser-window-focus', (event, win) => {
8 | let __updateWin;
9 |
10 | // Set logger
11 | autoUpdater.logger = log;
12 | autoUpdater.logger.transports.file.level = 'info';
13 |
14 | // Configure updater
15 | autoUpdater.allowPrerelease = false;
16 | autoUpdater.autoDownload = false;
17 |
18 | autoUpdater.on('update-available', ({version, releaseNotes}) => {
19 | if (__updateWin) {
20 | return;
21 | }
22 |
23 | win.webContents.send('update-available', {
24 | version,
25 | releaseNotes,
26 | currentVersion: app.getVersion()
27 | });
28 |
29 | __updateWin = win;
30 |
31 | __updateWin.on('close', () => {
32 | __updateWin = null;
33 | });
34 | });
35 |
36 | autoUpdater.on('update-not-available', () => {
37 | if (__updateWin) return;
38 |
39 | if (isAutomaticallyCheckingForUpdates) {
40 | isAutomaticallyCheckingForUpdates = false;
41 | return;
42 | }
43 |
44 | win.webContents.send('update-not-available');
45 | });
46 |
47 | autoUpdater.on('update-downloaded', () => {
48 | autoUpdater.quitAndInstall();
49 | });
50 |
51 | autoUpdater.on('download-progress', progress => {
52 | if (__updateWin) {
53 | __updateWin.webContents.send('download-progress', progress);
54 | }
55 | });
56 |
57 | autoUpdater.on('error', error => {
58 | if (__updateWin) {
59 | __updateWin.webContents.send('update-error', error);
60 | }
61 | });
62 |
63 | ipcMain.on('download-update', () => {
64 | if (process.env.NODE_ENV === 'production') autoUpdater.downloadUpdate();
65 | });
66 |
67 | ipcMain.on('check-update-manually', () => {
68 | if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates();
69 | });
70 | });
71 |
72 | export function checkForUpdates () {
73 | if (process.env.NODE_ENV !== 'production') return;
74 |
75 | isAutomaticallyCheckingForUpdates = true;
76 | autoUpdater.checkForUpdates();
77 | }
78 |
--------------------------------------------------------------------------------
/src/renderer/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
48 |
--------------------------------------------------------------------------------
/src/renderer/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/.gitkeep
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/128x128.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/16x16.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/24x24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/24x24.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/256x256.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/32x32.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/48x48.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/512x512.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/64x64.png
--------------------------------------------------------------------------------
/src/renderer/assets/app/icons/96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/app/icons/96x96.png
--------------------------------------------------------------------------------
/src/renderer/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/src/renderer/assets/logo.png
--------------------------------------------------------------------------------
/src/renderer/assets/logo_heart.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
50 |
--------------------------------------------------------------------------------
/src/renderer/assets/logo_sync.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
56 |
--------------------------------------------------------------------------------
/src/renderer/components/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 | Author: Rida Amirini
14 |
15 |
16 |
17 |
18 | Version: v{{version}}
19 |
20 |
21 |
22 |
23 | Latest version: v{{latest}}
24 |
25 | {{ updateAvailable ? 'Update' : 'Check for update'}}
26 |
27 |
28 |
29 |
30 |
31 |
32 | GitHub: ImapSync Client @GitHub
33 |
34 |
35 |
36 |
37 | ImapSync binary: v{{ imapsyncVersion }}
38 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
116 |
--------------------------------------------------------------------------------
/src/renderer/components/Add/MailboxForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | Add
38 |
39 |
40 | Add
41 |
42 |
43 | Migrate
44 | Abort
45 |
46 |
47 |
52 | Do you really want to end the process?
53 |
57 |
58 |
59 |
60 |
61 |
275 |
--------------------------------------------------------------------------------
/src/renderer/components/ImportCsvButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/renderer/components/MainComponent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | imapsync
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 |
113 |
114 |
--------------------------------------------------------------------------------
/src/renderer/components/QueueTable/QueueTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
14 |
18 |
19 |
23 |
24 |
25 |
29 |
30 |
34 |
35 |
38 |
39 |
40 |
44 |
45 |
50 |
51 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
88 |
89 |
--------------------------------------------------------------------------------
/src/renderer/components/QueueTable/QueueTablePassword.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ password }}
5 |
6 |
7 |
8 | ········
9 |
10 |
16 |
17 |
18 |
19 |
20 |
41 |
--------------------------------------------------------------------------------
/src/renderer/components/ShellAlikeBox.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
16 |
17 |
19 |
20 |
21 |
22 |
23 |
83 |
--------------------------------------------------------------------------------
/src/renderer/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import { webFrame } from 'electron';
3 | import axios from 'axios';
4 | import ElementUI from 'element-ui';
5 | import 'element-ui/lib/theme-chalk/index.css';
6 |
7 | import App from './App';
8 | import router from './router';
9 | import store from './store';
10 |
11 | Vue.use(ElementUI);
12 |
13 | if (!process.env.IS_WEB) Vue.use(require('vue-electron'));
14 | Vue.http = Vue.prototype.$http = axios;
15 | Vue.config.productionTip = false;
16 |
17 | /* eslint-disable no-new */
18 | new Vue({
19 | components: { App },
20 | router,
21 | store,
22 | template: ''
23 | }).$mount('#app');
24 |
25 | // WebFrame disable zoom in/out
26 | webFrame.setVisualZoomLevelLimits(1, 1);
27 | webFrame.setLayoutZoomLevelLimits(0, 0);
28 |
--------------------------------------------------------------------------------
/src/renderer/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Router from 'vue-router';
3 |
4 | Vue.use(Router);
5 |
6 | export default new Router({
7 | routes: [
8 | {
9 | path: '/',
10 | name: 'main-component',
11 | component: require('@/components/MainComponent').default
12 | },
13 | {
14 | path: '*',
15 | redirect: '/'
16 | }
17 | ]
18 | });
19 |
--------------------------------------------------------------------------------
/src/renderer/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 |
4 | import modules from './modules';
5 |
6 | Vue.use(Vuex);
7 |
8 | export default new Vuex.Store({
9 | modules,
10 | strict: process.env.NODE_ENV !== 'production'
11 | });
12 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/Counter.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | main: 0
3 | };
4 |
5 | const mutations = {
6 | DECREMENT_MAIN_COUNTER (state) {
7 | state.main--;
8 | },
9 | INCREMENT_MAIN_COUNTER (state) {
10 | state.main++;
11 | }
12 | };
13 |
14 | const actions = {
15 | someAsyncTask ({ commit }) {
16 | // do something async
17 | commit('INCREMENT_MAIN_COUNTER');
18 | }
19 | };
20 |
21 | export default {
22 | state,
23 | mutations,
24 | actions
25 | };
26 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/EventBus.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | export default new Vue();
3 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/Mailboxes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by ridaam on 26.11.17.
3 | */
4 |
5 | const state = {
6 | list: []
7 | };
8 |
9 | if (process.env.NODE_ENV !== 'production') {
10 | state.list = [
11 | {
12 | mailbox_from: 'test1',
13 | password_from: 'secret1',
14 | imap_from: 'test1.lamiral.info',
15 | mailbox_to: 'test2',
16 | password_to: 'secret2',
17 | imap_to: 'test2.lamiral.info'
18 | }
19 | ];
20 | }
21 |
22 | const mutations = {
23 | resetList (state, list) {
24 | state.list = [];
25 | state.list = state.list.concat(list);
26 | },
27 | addMailbox (state, mailbox) {
28 | state.list.push(mailbox);
29 | },
30 | removeMailbox (state, index) {
31 | state.list.splice(index, 1);
32 | }
33 | };
34 |
35 | const actions = {
36 | resetList ({ commit }, payload) {
37 | commit('resetList', payload);
38 | },
39 | addMailbox ({ commit }, payload) {
40 | commit('addMailbox', payload);
41 | },
42 | removeMailbox ({ commit }, payload) {
43 | commit('removeMailbox', payload);
44 | }
45 | };
46 |
47 | export default {
48 | state,
49 | mutations,
50 | actions
51 | };
52 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/ShellHistory.js:
--------------------------------------------------------------------------------
1 | // import app from '../../../../package.json';
2 | import revision from '../../../../revision.json';
3 |
4 | const WelcomeLine = {
5 | html: 'Welcome to imapsync ',
6 | color: null
7 | };
8 | const VersionLine = {
9 | html: 'Version ' + revision.version,
10 | color: null
11 | };
12 |
13 | const state = {
14 | output: [
15 | WelcomeLine,
16 | VersionLine
17 | ]
18 | };
19 |
20 | const mutations = {
21 | resetOutput (state, output) {
22 | state.output = [];
23 | state.output = state.output.concat(output);
24 | state.output.unshift(WelcomeLine, VersionLine);
25 | },
26 | addLine (state, line) {
27 | state.output.push({
28 | html: line,
29 | color: null
30 | });
31 | },
32 | addWarning (state, line) {
33 | state.output.push({
34 | html: line,
35 | color: 'yellow'
36 | });
37 | },
38 | addError (state, line) {
39 | state.output.push({
40 | html: line,
41 | color: 'red'
42 | });
43 | }
44 | };
45 |
46 | const actions = {
47 | resetOutput ({ commit }, payload) {
48 | commit('resetOutput', payload);
49 | },
50 | addLine ({ commit }, payload) {
51 | commit('addLine', payload);
52 | },
53 | addWarning ({ commit }, payload) {
54 | commit('addWarning', payload);
55 | },
56 | addError ({ commit }, payload) {
57 | commit('addError', payload);
58 | }
59 | };
60 |
61 | export default {
62 | state,
63 | mutations,
64 | actions
65 | };
66 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/Version.js:
--------------------------------------------------------------------------------
1 | import app from '../../../../package.json';
2 |
3 | const state = {
4 | version: app.version,
5 | latest: app.version
6 | };
7 |
8 | const mutations = {
9 | setLatestVersion (state, version) {
10 | state.latest = version;
11 | }
12 | };
13 |
14 | const actions = {};
15 |
16 | export default {
17 | state,
18 | mutations,
19 | actions
20 | };
21 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The file enables `@/store/index.js` to import all vuex modules
3 | * in a one-shot manner. There should not be any reason to edit this file.
4 | */
5 |
6 | const files = require.context('.', false, /\.js$/);
7 | const modules = {};
8 |
9 | files.keys().forEach(key => {
10 | if (key === './index.js') return;
11 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default;
12 | });
13 |
14 | export default modules;
15 |
--------------------------------------------------------------------------------
/static/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ridaamirini/ImapSyncClient/23070ab730323ce1f3e1238dfbee5a07579a41c4/static/.gitkeep
--------------------------------------------------------------------------------
/test.csv:
--------------------------------------------------------------------------------
1 | test1.lamiral.info;test1;secret1;test2.lamiral.info;test2;secret2
2 |
--------------------------------------------------------------------------------