rails 3.2.2 added tweeter bootstrap
This commit is contained in:
parent
74c23fa0d1
commit
cacd9575d0
5
AUTHORS
Executable file
5
AUTHORS
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
* Luben Manolov <luben.manolov@gmail.com>
|
||||||
|
* Nick Penkov <nick.penkov@gmail.com>
|
||||||
|
* Eugene Korbut
|
||||||
|
* Emilio Blanco
|
||||||
|
* Wojciech Todryk <wojciech(at)todryk(dot).pl>
|
19
CHANGES.markdown
Executable file
19
CHANGES.markdown
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
#### 0.8.6
|
||||||
|
|
||||||
|
* new calendar view
|
||||||
|
|
||||||
|
#### 0.8.5
|
||||||
|
|
||||||
|
* servers view
|
||||||
|
* identity modification
|
||||||
|
|
||||||
|
#### 0.8.4
|
||||||
|
|
||||||
|
* calendar view as separate gem
|
||||||
|
* adding bluecloth for rendering markdown text
|
||||||
|
|
||||||
|
#### 0.8.3
|
||||||
|
|
||||||
|
* export, imports of contact
|
7
Gemfile
7
Gemfile
|
@ -37,3 +37,10 @@ gem 'jquery-rails'
|
||||||
|
|
||||||
# To use debugger
|
# To use debugger
|
||||||
# gem 'ruby-debug'
|
# gem 'ruby-debug'
|
||||||
|
|
||||||
|
gem 'will_paginate'
|
||||||
|
gem "ezcrypto"
|
||||||
|
gem "calendar_view"
|
||||||
|
gem 'bluecloth'
|
||||||
|
gem 'sass'
|
||||||
|
gem 'haml'
|
||||||
|
|
12
Gemfile.lock
12
Gemfile.lock
|
@ -29,7 +29,10 @@ GEM
|
||||||
i18n (~> 0.6)
|
i18n (~> 0.6)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
arel (3.0.2)
|
arel (3.0.2)
|
||||||
|
bluecloth (2.2.0)
|
||||||
builder (3.0.0)
|
builder (3.0.0)
|
||||||
|
calendar_view (0.0.6)
|
||||||
|
rails (>= 3.0.0)
|
||||||
coffee-rails (3.2.2)
|
coffee-rails (3.2.2)
|
||||||
coffee-script (>= 2.2.0)
|
coffee-script (>= 2.2.0)
|
||||||
railties (~> 3.2.0)
|
railties (~> 3.2.0)
|
||||||
|
@ -40,6 +43,8 @@ GEM
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
execjs (1.3.0)
|
execjs (1.3.0)
|
||||||
multi_json (~> 1.0)
|
multi_json (~> 1.0)
|
||||||
|
ezcrypto (0.7.2)
|
||||||
|
haml (3.1.4)
|
||||||
hike (1.2.1)
|
hike (1.2.1)
|
||||||
i18n (0.6.0)
|
i18n (0.6.0)
|
||||||
journey (1.0.3)
|
journey (1.0.3)
|
||||||
|
@ -98,15 +103,22 @@ GEM
|
||||||
uglifier (1.2.3)
|
uglifier (1.2.3)
|
||||||
execjs (>= 0.3.0)
|
execjs (>= 0.3.0)
|
||||||
multi_json (>= 1.0.2)
|
multi_json (>= 1.0.2)
|
||||||
|
will_paginate (3.0.3)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
bluecloth
|
||||||
|
calendar_view
|
||||||
coffee-rails (~> 3.2.1)
|
coffee-rails (~> 3.2.1)
|
||||||
|
ezcrypto
|
||||||
|
haml
|
||||||
jquery-rails
|
jquery-rails
|
||||||
json
|
json
|
||||||
mysql2
|
mysql2
|
||||||
rails (= 3.2.2)
|
rails (= 3.2.2)
|
||||||
|
sass
|
||||||
sass-rails (~> 3.2.3)
|
sass-rails (~> 3.2.3)
|
||||||
uglifier (>= 1.0.3)
|
uglifier (>= 1.0.3)
|
||||||
|
will_paginate
|
||||||
|
|
20
TODO.markdown
Executable file
20
TODO.markdown
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
## Todo
|
||||||
|
|
||||||
|
app/controllers/folders_controller.rb:
|
||||||
|
|
||||||
|
* [ 30] [TODO] recreate local copy of folders
|
||||||
|
* [ 99] [TODO] save system folders
|
||||||
|
|
||||||
|
app/controllers/messages_controller.rb:
|
||||||
|
|
||||||
|
* [101] [FIXME] missing fields and support arrays
|
||||||
|
|
||||||
|
app/controllers/messages_ops_controller.rb:
|
||||||
|
|
||||||
|
* [249] [FIXME] edit does not support attachments
|
||||||
|
* [304] [TODO] check if email address is valid if not get address from contacts
|
||||||
|
|
||||||
|
app/models/prefs.rb:
|
||||||
|
|
||||||
|
* [ 19] [TODO] move refresh to prefs and make refresh page with messages
|
||||||
|
|
24
UNLICENSE.markdown
Executable file
24
UNLICENSE.markdown
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
BIN
app/assets/images/glyphicons-halflings-white.png
Normal file
BIN
app/assets/images/glyphicons-halflings-white.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
app/assets/images/glyphicons-halflings.png
Normal file
BIN
app/assets/images/glyphicons-halflings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
app/assets/images/logo.png
Executable file
BIN
app/assets/images/logo.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
1
app/assets/javascripts/bootstrap.min.js
vendored
Normal file
1
app/assets/javascripts/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
app/assets/stylesheets/bootstrap-responsive.min.css
vendored
Normal file
4
app/assets/stylesheets/bootstrap-responsive.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
632
app/assets/stylesheets/bootstrap.min.css
vendored
Normal file
632
app/assets/stylesheets/bootstrap.min.css
vendored
Normal file
|
@ -0,0 +1,632 @@
|
||||||
|
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
|
||||||
|
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
|
||||||
|
audio:not([controls]){display:none;}
|
||||||
|
html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
|
||||||
|
a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
|
||||||
|
a:hover,a:active{outline:0;}
|
||||||
|
sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
|
||||||
|
sup{top:-0.5em;}
|
||||||
|
sub{bottom:-0.25em;}
|
||||||
|
img{max-width:100%;height:auto;border:0;-ms-interpolation-mode:bicubic;}
|
||||||
|
button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
|
||||||
|
button,input{*overflow:visible;line-height:normal;}
|
||||||
|
button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
|
||||||
|
button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
|
||||||
|
input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
|
||||||
|
input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
|
||||||
|
textarea{overflow:auto;vertical-align:top;}
|
||||||
|
.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
|
||||||
|
.clearfix:after{clear:both;}
|
||||||
|
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}
|
||||||
|
a{color:#0088cc;text-decoration:none;}
|
||||||
|
a:hover{color:#005580;text-decoration:underline;}
|
||||||
|
.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";}
|
||||||
|
.row:after{clear:both;}
|
||||||
|
[class*="span"]{float:left;margin-left:20px;}
|
||||||
|
.span1{width:60px;}
|
||||||
|
.span2{width:140px;}
|
||||||
|
.span3{width:220px;}
|
||||||
|
.span4{width:300px;}
|
||||||
|
.span5{width:380px;}
|
||||||
|
.span6{width:460px;}
|
||||||
|
.span7{width:540px;}
|
||||||
|
.span8{width:620px;}
|
||||||
|
.span9{width:700px;}
|
||||||
|
.span10{width:780px;}
|
||||||
|
.span11{width:860px;}
|
||||||
|
.span12,.container{width:940px;}
|
||||||
|
.offset1{margin-left:100px;}
|
||||||
|
.offset2{margin-left:180px;}
|
||||||
|
.offset3{margin-left:260px;}
|
||||||
|
.offset4{margin-left:340px;}
|
||||||
|
.offset5{margin-left:420px;}
|
||||||
|
.offset6{margin-left:500px;}
|
||||||
|
.offset7{margin-left:580px;}
|
||||||
|
.offset8{margin-left:660px;}
|
||||||
|
.offset9{margin-left:740px;}
|
||||||
|
.offset10{margin-left:820px;}
|
||||||
|
.offset11{margin-left:900px;}
|
||||||
|
.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";}
|
||||||
|
.row-fluid:after{clear:both;}
|
||||||
|
.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;}
|
||||||
|
.row-fluid>[class*="span"]:first-child{margin-left:0;}
|
||||||
|
.row-fluid>.span1{width:6.382978723%;}
|
||||||
|
.row-fluid>.span2{width:14.89361702%;}
|
||||||
|
.row-fluid>.span3{width:23.404255317%;}
|
||||||
|
.row-fluid>.span4{width:31.914893614%;}
|
||||||
|
.row-fluid>.span5{width:40.425531911%;}
|
||||||
|
.row-fluid>.span6{width:48.93617020799999%;}
|
||||||
|
.row-fluid>.span7{width:57.446808505%;}
|
||||||
|
.row-fluid>.span8{width:65.95744680199999%;}
|
||||||
|
.row-fluid>.span9{width:74.468085099%;}
|
||||||
|
.row-fluid>.span10{width:82.97872339599999%;}
|
||||||
|
.row-fluid>.span11{width:91.489361693%;}
|
||||||
|
.row-fluid>.span12{width:99.99999998999999%;}
|
||||||
|
.container{width:940px;margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";}
|
||||||
|
.container:after{clear:both;}
|
||||||
|
.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";}
|
||||||
|
.container-fluid:after{clear:both;}
|
||||||
|
p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;}
|
||||||
|
.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}
|
||||||
|
h1,h2,h3,h4,h5,h6{margin:0;font-weight:bold;color:#333333;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;}
|
||||||
|
h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}
|
||||||
|
h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}
|
||||||
|
h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;}
|
||||||
|
h4,h5,h6{line-height:18px;}
|
||||||
|
h4{font-size:14px;}h4 small{font-size:12px;}
|
||||||
|
h5{font-size:12px;}
|
||||||
|
h6{font-size:11px;color:#999999;text-transform:uppercase;}
|
||||||
|
.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}
|
||||||
|
.page-header h1{line-height:1;}
|
||||||
|
ul,ol{padding:0;margin:0 0 9px 25px;}
|
||||||
|
ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
|
||||||
|
ul{list-style:disc;}
|
||||||
|
ol{list-style:decimal;}
|
||||||
|
li{line-height:18px;}
|
||||||
|
ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
|
||||||
|
dl{margin-bottom:18px;}
|
||||||
|
dt,dd{line-height:18px;}
|
||||||
|
dt{font-weight:bold;}
|
||||||
|
dd{margin-left:9px;}
|
||||||
|
hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
|
||||||
|
strong{font-weight:bold;}
|
||||||
|
em{font-style:italic;}
|
||||||
|
.muted{color:#999999;}
|
||||||
|
abbr{font-size:90%;text-transform:uppercase;border-bottom:1px dotted #ddd;cursor:help;}
|
||||||
|
blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}
|
||||||
|
blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
|
||||||
|
blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
|
||||||
|
q:before,q:after,blockquote:before,blockquote:after{content:"";}
|
||||||
|
address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;}
|
||||||
|
small{font-size:100%;}
|
||||||
|
cite{font-style:normal;}
|
||||||
|
code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
|
||||||
|
code{padding:3px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}
|
||||||
|
pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;word-wrap:break-word;}pre.prettyprint{margin-bottom:18px;}
|
||||||
|
pre code{padding:0;color:inherit;background-color:transparent;border:0;}
|
||||||
|
.pre-scrollable{max-height:340px;overflow-y:scroll;}
|
||||||
|
form{margin:0 0 18px;}
|
||||||
|
fieldset{padding:0;margin:0;border:0;}
|
||||||
|
legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;}
|
||||||
|
label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;}
|
||||||
|
input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
|
||||||
|
label{display:block;margin-bottom:5px;color:#333333;}
|
||||||
|
input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
|
||||||
|
.uneditable-textarea{width:auto;height:auto;}
|
||||||
|
label input,label textarea,label select{display:block;}
|
||||||
|
input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0 \9;}
|
||||||
|
input[type="image"]{border:0;}
|
||||||
|
input[type="file"]{width:auto;padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
|
||||||
|
input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;}
|
||||||
|
select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;}
|
||||||
|
input[type="file"]{line-height:18px \9;}
|
||||||
|
select{width:220px;background-color:#ffffff;}
|
||||||
|
select[multiple],select[size]{height:auto;}
|
||||||
|
input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
|
||||||
|
textarea{height:auto;}
|
||||||
|
input[type="hidden"]{display:none;}
|
||||||
|
.radio,.checkbox{padding-left:18px;}
|
||||||
|
.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;}
|
||||||
|
.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
|
||||||
|
.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
|
||||||
|
.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
|
||||||
|
input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;}
|
||||||
|
input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;}
|
||||||
|
input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
|
||||||
|
.input-mini{width:60px;}
|
||||||
|
.input-small{width:90px;}
|
||||||
|
.input-medium{width:150px;}
|
||||||
|
.input-large{width:210px;}
|
||||||
|
.input-xlarge{width:270px;}
|
||||||
|
.input-xxlarge{width:530px;}
|
||||||
|
input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;}
|
||||||
|
input.span1,textarea.span1,.uneditable-input.span1{width:50px;}
|
||||||
|
input.span2,textarea.span2,.uneditable-input.span2{width:130px;}
|
||||||
|
input.span3,textarea.span3,.uneditable-input.span3{width:210px;}
|
||||||
|
input.span4,textarea.span4,.uneditable-input.span4{width:290px;}
|
||||||
|
input.span5,textarea.span5,.uneditable-input.span5{width:370px;}
|
||||||
|
input.span6,textarea.span6,.uneditable-input.span6{width:450px;}
|
||||||
|
input.span7,textarea.span7,.uneditable-input.span7{width:530px;}
|
||||||
|
input.span8,textarea.span8,.uneditable-input.span8{width:610px;}
|
||||||
|
input.span9,textarea.span9,.uneditable-input.span9{width:690px;}
|
||||||
|
input.span10,textarea.span10,.uneditable-input.span10{width:770px;}
|
||||||
|
input.span11,textarea.span11,.uneditable-input.span11{width:850px;}
|
||||||
|
input.span12,textarea.span12,.uneditable-input.span12{width:930px;}
|
||||||
|
input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;}
|
||||||
|
.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
|
||||||
|
.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;}
|
||||||
|
.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
|
||||||
|
.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
|
||||||
|
.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;}
|
||||||
|
.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
|
||||||
|
.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
|
||||||
|
.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;}
|
||||||
|
.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
|
||||||
|
input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
|
||||||
|
.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;}
|
||||||
|
.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
|
||||||
|
:-moz-placeholder{color:#999999;}
|
||||||
|
::-webkit-input-placeholder{color:#999999;}
|
||||||
|
.help-block{display:block;margin-top:5px;margin-bottom:0;color:#999999;}
|
||||||
|
.help-inline{display:inline-block;*display:inline;*zoom:1;margin-bottom:9px;vertical-align:middle;padding-left:5px;}
|
||||||
|
.input-prepend,.input-append{margin-bottom:5px;*zoom:1;}.input-prepend:before,.input-append:before,.input-prepend:after,.input-append:after{display:table;content:"";}
|
||||||
|
.input-prepend:after,.input-append:after{clear:both;}
|
||||||
|
.input-prepend input,.input-append input,.input-prepend .uneditable-input,.input-append .uneditable-input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;}
|
||||||
|
.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;}
|
||||||
|
.input-prepend .add-on,.input-append .add-on{float:left;display:block;width:auto;min-width:16px;height:18px;margin-right:-1px;padding:4px 5px;font-weight:normal;line-height:18px;color:#999999;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
|
||||||
|
.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;}
|
||||||
|
.input-prepend .add-on{*margin-top:1px;}
|
||||||
|
.input-append input,.input-append .uneditable-input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
|
||||||
|
.input-append .uneditable-input{border-left-color:#eee;border-right-color:#ccc;}
|
||||||
|
.input-append .add-on{margin-right:0;margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
|
||||||
|
.input-append input:first-child{*margin-left:-160px;}.input-append input:first-child+.add-on{*margin-left:-21px;}
|
||||||
|
.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;}
|
||||||
|
.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input{display:inline-block;margin-bottom:0;}
|
||||||
|
.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
|
||||||
|
.form-search label,.form-inline label,.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{display:inline-block;}
|
||||||
|
.form-search .input-append .add-on,.form-inline .input-prepend .add-on,.form-search .input-append .add-on,.form-inline .input-prepend .add-on{vertical-align:middle;}
|
||||||
|
.form-search .radio,.form-inline .radio,.form-search .checkbox,.form-inline .checkbox{margin-bottom:0;vertical-align:middle;}
|
||||||
|
.control-group{margin-bottom:9px;}
|
||||||
|
legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;}
|
||||||
|
.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";}
|
||||||
|
.form-horizontal .control-group:after{clear:both;}
|
||||||
|
.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;}
|
||||||
|
.form-horizontal .controls{margin-left:160px;}
|
||||||
|
.form-horizontal .form-actions{padding-left:160px;}
|
||||||
|
table{max-width:100%;border-collapse:collapse;border-spacing:0;}
|
||||||
|
.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #ddd;}
|
||||||
|
.table th{font-weight:bold;}
|
||||||
|
.table thead th{vertical-align:bottom;}
|
||||||
|
.table thead:first-child tr th,.table thead:first-child tr td{border-top:0;}
|
||||||
|
.table tbody+tbody{border-top:2px solid #ddd;}
|
||||||
|
.table-condensed th,.table-condensed td{padding:4px 5px;}
|
||||||
|
.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th+th,.table-bordered td+td,.table-bordered th+td,.table-bordered td+th{border-left:1px solid #ddd;}
|
||||||
|
.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
|
||||||
|
.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
|
||||||
|
.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
|
||||||
|
.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
|
||||||
|
.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
|
||||||
|
.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
|
||||||
|
.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}
|
||||||
|
table .span1{float:none;width:44px;margin-left:0;}
|
||||||
|
table .span2{float:none;width:124px;margin-left:0;}
|
||||||
|
table .span3{float:none;width:204px;margin-left:0;}
|
||||||
|
table .span4{float:none;width:284px;margin-left:0;}
|
||||||
|
table .span5{float:none;width:364px;margin-left:0;}
|
||||||
|
table .span6{float:none;width:444px;margin-left:0;}
|
||||||
|
table .span7{float:none;width:524px;margin-left:0;}
|
||||||
|
table .span8{float:none;width:604px;margin-left:0;}
|
||||||
|
table .span9{float:none;width:684px;margin-left:0;}
|
||||||
|
table .span10{float:none;width:764px;margin-left:0;}
|
||||||
|
table .span11{float:none;width:844px;margin-left:0;}
|
||||||
|
table .span12{float:none;width:924px;margin-left:0;}
|
||||||
|
[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;}
|
||||||
|
.icon-white{background-image:url("../img/glyphicons-halflings-white.png");}
|
||||||
|
.icon-glass{background-position:0 0;}
|
||||||
|
.icon-music{background-position:-24px 0;}
|
||||||
|
.icon-search{background-position:-48px 0;}
|
||||||
|
.icon-envelope{background-position:-72px 0;}
|
||||||
|
.icon-heart{background-position:-96px 0;}
|
||||||
|
.icon-star{background-position:-120px 0;}
|
||||||
|
.icon-star-empty{background-position:-144px 0;}
|
||||||
|
.icon-user{background-position:-168px 0;}
|
||||||
|
.icon-film{background-position:-192px 0;}
|
||||||
|
.icon-th-large{background-position:-216px 0;}
|
||||||
|
.icon-th{background-position:-240px 0;}
|
||||||
|
.icon-th-list{background-position:-264px 0;}
|
||||||
|
.icon-ok{background-position:-288px 0;}
|
||||||
|
.icon-remove{background-position:-312px 0;}
|
||||||
|
.icon-zoom-in{background-position:-336px 0;}
|
||||||
|
.icon-zoom-out{background-position:-360px 0;}
|
||||||
|
.icon-off{background-position:-384px 0;}
|
||||||
|
.icon-signal{background-position:-408px 0;}
|
||||||
|
.icon-cog{background-position:-432px 0;}
|
||||||
|
.icon-trash{background-position:-456px 0;}
|
||||||
|
.icon-home{background-position:0 -24px;}
|
||||||
|
.icon-file{background-position:-24px -24px;}
|
||||||
|
.icon-time{background-position:-48px -24px;}
|
||||||
|
.icon-road{background-position:-72px -24px;}
|
||||||
|
.icon-download-alt{background-position:-96px -24px;}
|
||||||
|
.icon-download{background-position:-120px -24px;}
|
||||||
|
.icon-upload{background-position:-144px -24px;}
|
||||||
|
.icon-inbox{background-position:-168px -24px;}
|
||||||
|
.icon-play-circle{background-position:-192px -24px;}
|
||||||
|
.icon-repeat{background-position:-216px -24px;}
|
||||||
|
.icon-refresh{background-position:-240px -24px;}
|
||||||
|
.icon-list-alt{background-position:-264px -24px;}
|
||||||
|
.icon-lock{background-position:-287px -24px;}
|
||||||
|
.icon-flag{background-position:-312px -24px;}
|
||||||
|
.icon-headphones{background-position:-336px -24px;}
|
||||||
|
.icon-volume-off{background-position:-360px -24px;}
|
||||||
|
.icon-volume-down{background-position:-384px -24px;}
|
||||||
|
.icon-volume-up{background-position:-408px -24px;}
|
||||||
|
.icon-qrcode{background-position:-432px -24px;}
|
||||||
|
.icon-barcode{background-position:-456px -24px;}
|
||||||
|
.icon-tag{background-position:0 -48px;}
|
||||||
|
.icon-tags{background-position:-25px -48px;}
|
||||||
|
.icon-book{background-position:-48px -48px;}
|
||||||
|
.icon-bookmark{background-position:-72px -48px;}
|
||||||
|
.icon-print{background-position:-96px -48px;}
|
||||||
|
.icon-camera{background-position:-120px -48px;}
|
||||||
|
.icon-font{background-position:-144px -48px;}
|
||||||
|
.icon-bold{background-position:-167px -48px;}
|
||||||
|
.icon-italic{background-position:-192px -48px;}
|
||||||
|
.icon-text-height{background-position:-216px -48px;}
|
||||||
|
.icon-text-width{background-position:-240px -48px;}
|
||||||
|
.icon-align-left{background-position:-264px -48px;}
|
||||||
|
.icon-align-center{background-position:-288px -48px;}
|
||||||
|
.icon-align-right{background-position:-312px -48px;}
|
||||||
|
.icon-align-justify{background-position:-336px -48px;}
|
||||||
|
.icon-list{background-position:-360px -48px;}
|
||||||
|
.icon-indent-left{background-position:-384px -48px;}
|
||||||
|
.icon-indent-right{background-position:-408px -48px;}
|
||||||
|
.icon-facetime-video{background-position:-432px -48px;}
|
||||||
|
.icon-picture{background-position:-456px -48px;}
|
||||||
|
.icon-pencil{background-position:0 -72px;}
|
||||||
|
.icon-map-marker{background-position:-24px -72px;}
|
||||||
|
.icon-adjust{background-position:-48px -72px;}
|
||||||
|
.icon-tint{background-position:-72px -72px;}
|
||||||
|
.icon-edit{background-position:-96px -72px;}
|
||||||
|
.icon-share{background-position:-120px -72px;}
|
||||||
|
.icon-check{background-position:-144px -72px;}
|
||||||
|
.icon-move{background-position:-168px -72px;}
|
||||||
|
.icon-step-backward{background-position:-192px -72px;}
|
||||||
|
.icon-fast-backward{background-position:-216px -72px;}
|
||||||
|
.icon-backward{background-position:-240px -72px;}
|
||||||
|
.icon-play{background-position:-264px -72px;}
|
||||||
|
.icon-pause{background-position:-288px -72px;}
|
||||||
|
.icon-stop{background-position:-312px -72px;}
|
||||||
|
.icon-forward{background-position:-336px -72px;}
|
||||||
|
.icon-fast-forward{background-position:-360px -72px;}
|
||||||
|
.icon-step-forward{background-position:-384px -72px;}
|
||||||
|
.icon-eject{background-position:-408px -72px;}
|
||||||
|
.icon-chevron-left{background-position:-432px -72px;}
|
||||||
|
.icon-chevron-right{background-position:-456px -72px;}
|
||||||
|
.icon-plus-sign{background-position:0 -96px;}
|
||||||
|
.icon-minus-sign{background-position:-24px -96px;}
|
||||||
|
.icon-remove-sign{background-position:-48px -96px;}
|
||||||
|
.icon-ok-sign{background-position:-72px -96px;}
|
||||||
|
.icon-question-sign{background-position:-96px -96px;}
|
||||||
|
.icon-info-sign{background-position:-120px -96px;}
|
||||||
|
.icon-screenshot{background-position:-144px -96px;}
|
||||||
|
.icon-remove-circle{background-position:-168px -96px;}
|
||||||
|
.icon-ok-circle{background-position:-192px -96px;}
|
||||||
|
.icon-ban-circle{background-position:-216px -96px;}
|
||||||
|
.icon-arrow-left{background-position:-240px -96px;}
|
||||||
|
.icon-arrow-right{background-position:-264px -96px;}
|
||||||
|
.icon-arrow-up{background-position:-289px -96px;}
|
||||||
|
.icon-arrow-down{background-position:-312px -96px;}
|
||||||
|
.icon-share-alt{background-position:-336px -96px;}
|
||||||
|
.icon-resize-full{background-position:-360px -96px;}
|
||||||
|
.icon-resize-small{background-position:-384px -96px;}
|
||||||
|
.icon-plus{background-position:-408px -96px;}
|
||||||
|
.icon-minus{background-position:-433px -96px;}
|
||||||
|
.icon-asterisk{background-position:-456px -96px;}
|
||||||
|
.icon-exclamation-sign{background-position:0 -120px;}
|
||||||
|
.icon-gift{background-position:-24px -120px;}
|
||||||
|
.icon-leaf{background-position:-48px -120px;}
|
||||||
|
.icon-fire{background-position:-72px -120px;}
|
||||||
|
.icon-eye-open{background-position:-96px -120px;}
|
||||||
|
.icon-eye-close{background-position:-120px -120px;}
|
||||||
|
.icon-warning-sign{background-position:-144px -120px;}
|
||||||
|
.icon-plane{background-position:-168px -120px;}
|
||||||
|
.icon-calendar{background-position:-192px -120px;}
|
||||||
|
.icon-random{background-position:-216px -120px;}
|
||||||
|
.icon-comment{background-position:-240px -120px;}
|
||||||
|
.icon-magnet{background-position:-264px -120px;}
|
||||||
|
.icon-chevron-up{background-position:-288px -120px;}
|
||||||
|
.icon-chevron-down{background-position:-313px -119px;}
|
||||||
|
.icon-retweet{background-position:-336px -120px;}
|
||||||
|
.icon-shopping-cart{background-position:-360px -120px;}
|
||||||
|
.icon-folder-close{background-position:-384px -120px;}
|
||||||
|
.icon-folder-open{background-position:-408px -120px;}
|
||||||
|
.icon-resize-vertical{background-position:-432px -119px;}
|
||||||
|
.icon-resize-horizontal{background-position:-456px -118px;}
|
||||||
|
.dropdown{position:relative;}
|
||||||
|
.dropdown-toggle{*margin-bottom:-3px;}
|
||||||
|
.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
|
||||||
|
.caret{display:inline-block;width:0;height:0;text-indent:-99999px;*text-indent:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"\2193";}
|
||||||
|
.dropdown .caret{margin-top:8px;margin-left:2px;}
|
||||||
|
.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);}
|
||||||
|
.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;_width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.bottom-up{top:auto;bottom:100%;margin-bottom:2px;}
|
||||||
|
.dropdown-menu .divider{height:1px;margin:5px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;}
|
||||||
|
.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#555555;white-space:nowrap;}
|
||||||
|
.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;}
|
||||||
|
.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);}
|
||||||
|
.dropdown.open .dropdown-menu{display:block;}
|
||||||
|
.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
|
||||||
|
.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
|
||||||
|
.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;}
|
||||||
|
.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;}
|
||||||
|
.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;}
|
||||||
|
.btn{display:inline-block;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);*margin-left:.3em;}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;}
|
||||||
|
.btn:active,.btn.active{background-color:#cccccc \9;}
|
||||||
|
.btn:first-child{*margin-left:0;}
|
||||||
|
.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
|
||||||
|
.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
|
||||||
|
.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;outline:0;}
|
||||||
|
.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
|
||||||
|
.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
|
||||||
|
.btn-large [class^="icon-"]{margin-top:1px;}
|
||||||
|
.btn-small{padding:5px 9px;font-size:11px;line-height:16px;}
|
||||||
|
.btn-small [class^="icon-"]{margin-top:-1px;}
|
||||||
|
.btn-mini{padding:2px 6px;font-size:11px;line-height:14px;}
|
||||||
|
.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;}
|
||||||
|
.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-dark.active{color:rgba(255, 255, 255, 0.75);}
|
||||||
|
.btn-primary{background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-ms-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(top, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0044cc;}
|
||||||
|
.btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
|
||||||
|
.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;}
|
||||||
|
.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
|
||||||
|
.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;}
|
||||||
|
.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
|
||||||
|
.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;}
|
||||||
|
.btn-success:active,.btn-success.active{background-color:#408140 \9;}
|
||||||
|
.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;}
|
||||||
|
.btn-info:active,.btn-info.active{background-color:#24748c \9;}
|
||||||
|
.btn-inverse{background-color:#393939;background-image:-moz-linear-gradient(top, #454545, #262626);background-image:-ms-linear-gradient(top, #454545, #262626);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626));background-image:-webkit-linear-gradient(top, #454545, #262626);background-image:-o-linear-gradient(top, #454545, #262626);background-image:linear-gradient(top, #454545, #262626);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0);border-color:#262626 #262626 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#262626;}
|
||||||
|
.btn-inverse:active,.btn-inverse.active{background-color:#0c0c0c \9;}
|
||||||
|
button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
|
||||||
|
button.btn.large,input[type="submit"].btn.large{*padding-top:7px;*padding-bottom:7px;}
|
||||||
|
button.btn.small,input[type="submit"].btn.small{*padding-top:3px;*padding-bottom:3px;}
|
||||||
|
.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";}
|
||||||
|
.btn-group:after{clear:both;}
|
||||||
|
.btn-group:first-child{*margin-left:0;}
|
||||||
|
.btn-group+.btn-group{margin-left:5px;}
|
||||||
|
.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;}
|
||||||
|
.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
|
||||||
|
.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
|
||||||
|
.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
|
||||||
|
.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
|
||||||
|
.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
|
||||||
|
.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;}
|
||||||
|
.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
|
||||||
|
.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:5px;*padding-bottom:5px;}
|
||||||
|
.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
|
||||||
|
.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);}
|
||||||
|
.btn .caret{margin-top:7px;margin-left:0;}
|
||||||
|
.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);}
|
||||||
|
.btn-primary .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);}
|
||||||
|
.btn-small .caret{margin-top:4px;}
|
||||||
|
.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
|
||||||
|
.alert,.alert-heading{color:#c09853;}
|
||||||
|
.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;}
|
||||||
|
.alert-success{background-color:#dff0d8;border-color:#d6e9c6;}
|
||||||
|
.alert-success,.alert-success .alert-heading{color:#468847;}
|
||||||
|
.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;}
|
||||||
|
.alert-danger,.alert-error,.alert-danger .alert-heading,.alert-error .alert-heading{color:#b94a48;}
|
||||||
|
.alert-info{background-color:#d9edf7;border-color:#bce8f1;}
|
||||||
|
.alert-info,.alert-info .alert-heading{color:#3a87ad;}
|
||||||
|
.alert-block{padding-top:14px;padding-bottom:14px;}
|
||||||
|
.alert-block>p,.alert-block>ul{margin-bottom:0;}
|
||||||
|
.alert-block p+p{margin-top:5px;}
|
||||||
|
.nav{margin-left:0;margin-bottom:18px;list-style:none;}
|
||||||
|
.nav>li>a{display:block;}
|
||||||
|
.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
|
||||||
|
.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
|
||||||
|
.nav li+.nav-header{margin-top:9px;}
|
||||||
|
.nav-list{padding-left:14px;padding-right:14px;margin-bottom:0;}
|
||||||
|
.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
|
||||||
|
.nav-list>li>a{padding:3px 15px;}
|
||||||
|
.nav-list .active>a,.nav-list .active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
|
||||||
|
.nav-list [class^="icon-"]{margin-right:2px;}
|
||||||
|
.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";}
|
||||||
|
.nav-tabs:after,.nav-pills:after{clear:both;}
|
||||||
|
.nav-tabs>li,.nav-pills>li{float:left;}
|
||||||
|
.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
|
||||||
|
.nav-tabs{border-bottom:1px solid #ddd;}
|
||||||
|
.nav-tabs>li{margin-bottom:-1px;}
|
||||||
|
.nav-tabs>li>a{padding-top:9px;padding-bottom:9px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}
|
||||||
|
.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
|
||||||
|
.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
|
||||||
|
.nav-pills .active>a,.nav-pills .active>a:hover{color:#ffffff;background-color:#0088cc;}
|
||||||
|
.nav-stacked>li{float:none;}
|
||||||
|
.nav-stacked>li>a{margin-right:0;}
|
||||||
|
.nav-tabs.nav-stacked{border-bottom:0;}
|
||||||
|
.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
|
||||||
|
.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
|
||||||
|
.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
|
||||||
|
.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
|
||||||
|
.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
|
||||||
|
.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
|
||||||
|
.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;}
|
||||||
|
.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
|
||||||
|
.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;margin-top:6px;}
|
||||||
|
.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;}
|
||||||
|
.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;}
|
||||||
|
.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;}
|
||||||
|
.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
|
||||||
|
.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
|
||||||
|
.tabs-stacked .open>a:hover{border-color:#999999;}
|
||||||
|
.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";}
|
||||||
|
.tabbable:after{clear:both;}
|
||||||
|
.tab-content{overflow:hidden;}
|
||||||
|
.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;}
|
||||||
|
.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
|
||||||
|
.tab-content>.active,.pill-content>.active{display:block;}
|
||||||
|
.tabs-below .nav-tabs{border-top:1px solid #ddd;}
|
||||||
|
.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;}
|
||||||
|
.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}
|
||||||
|
.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;}
|
||||||
|
.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;}
|
||||||
|
.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
|
||||||
|
.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
|
||||||
|
.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
|
||||||
|
.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
|
||||||
|
.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
|
||||||
|
.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
|
||||||
|
.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
|
||||||
|
.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
|
||||||
|
.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
|
||||||
|
.navbar{overflow:visible;margin-bottom:18px;}
|
||||||
|
.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);}
|
||||||
|
.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;}
|
||||||
|
.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;}
|
||||||
|
.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}
|
||||||
|
.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
|
||||||
|
.nav-collapse.collapse{height:auto;}
|
||||||
|
.navbar .brand:hover{text-decoration:none;}
|
||||||
|
.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;}
|
||||||
|
.navbar .navbar-text{margin-bottom:0;line-height:40px;color:#999999;}.navbar .navbar-text a:hover{color:#ffffff;background-color:transparent;}
|
||||||
|
.navbar .btn,.navbar .btn-group{margin-top:5px;}
|
||||||
|
.navbar .btn-group .btn{margin-top:0;}
|
||||||
|
.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";}
|
||||||
|
.navbar-form:after{clear:both;}
|
||||||
|
.navbar-form input,.navbar-form select{display:inline-block;margin-top:5px;margin-bottom:0;}
|
||||||
|
.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
|
||||||
|
.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
|
||||||
|
.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;}
|
||||||
|
.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;color:rgba(255, 255, 255, 0.75);background:#666;background:rgba(255, 255, 255, 0.3);border:1px solid #111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query :-moz-placeholder{color:#eeeeee;}
|
||||||
|
.navbar-search .search-query::-webkit-input-placeholder{color:#eeeeee;}
|
||||||
|
.navbar-search .search-query:hover{color:#ffffff;background-color:#999999;background-color:rgba(255, 255, 255, 0.5);}
|
||||||
|
.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}
|
||||||
|
.navbar-fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030;}
|
||||||
|
.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
|
||||||
|
.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
|
||||||
|
.navbar .nav.pull-right{float:right;}
|
||||||
|
.navbar .nav>li{display:block;float:left;}
|
||||||
|
.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}
|
||||||
|
.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;}
|
||||||
|
.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;}
|
||||||
|
.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;}
|
||||||
|
.navbar .nav.pull-right{margin-left:10px;margin-right:0;}
|
||||||
|
.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}
|
||||||
|
.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
|
||||||
|
.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;}
|
||||||
|
.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);}
|
||||||
|
.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;}
|
||||||
|
.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;}
|
||||||
|
.navbar .nav.pull-right .dropdown-menu{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before{left:auto;right:12px;}
|
||||||
|
.navbar .nav.pull-right .dropdown-menu:after{left:auto;right:13px;}
|
||||||
|
.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;text-shadow:0 1px 0 #ffffff;}
|
||||||
|
.breadcrumb .divider{padding:0 5px;color:#999999;}
|
||||||
|
.breadcrumb .active a{color:#333333;}
|
||||||
|
.pagination{height:36px;margin:18px 0;}
|
||||||
|
.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
|
||||||
|
.pagination li{display:inline;}
|
||||||
|
.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;}
|
||||||
|
.pagination a:hover,.pagination .active a{background-color:#f5f5f5;}
|
||||||
|
.pagination .active a{color:#999999;cursor:default;}
|
||||||
|
.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;}
|
||||||
|
.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
|
||||||
|
.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
|
||||||
|
.pagination-centered{text-align:center;}
|
||||||
|
.pagination-right{text-align:right;}
|
||||||
|
.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";}
|
||||||
|
.pager:after{clear:both;}
|
||||||
|
.pager li{display:inline;}
|
||||||
|
.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
|
||||||
|
.pager a:hover{text-decoration:none;background-color:#f5f5f5;}
|
||||||
|
.pager .next a{float:right;}
|
||||||
|
.pager .previous a{float:left;}
|
||||||
|
.modal-open .dropdown-menu{z-index:2050;}
|
||||||
|
.modal-open .dropdown.open{*z-index:2050;}
|
||||||
|
.modal-open .popover{z-index:2060;}
|
||||||
|
.modal-open .tooltip{z-index:2070;}
|
||||||
|
.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
|
||||||
|
.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
|
||||||
|
.modal{position:fixed;top:50%;left:50%;z-index:1050;max-height:500px;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
|
||||||
|
.modal.fade.in{top:50%;}
|
||||||
|
.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
|
||||||
|
.modal-body{padding:15px;}
|
||||||
|
.modal-body .modal-form{margin-bottom:0;}
|
||||||
|
.modal-footer{padding:14px 15px 15px;margin-bottom:0;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";}
|
||||||
|
.modal-footer:after{clear:both;}
|
||||||
|
.modal-footer .btn{float:right;margin-left:5px;margin-bottom:0;}
|
||||||
|
.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
|
||||||
|
.tooltip.top{margin-top:-2px;}
|
||||||
|
.tooltip.right{margin-left:2px;}
|
||||||
|
.tooltip.bottom{margin-top:2px;}
|
||||||
|
.tooltip.left{margin-left:-2px;}
|
||||||
|
.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
|
||||||
|
.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
|
||||||
|
.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
|
||||||
|
.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
|
||||||
|
.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
|
||||||
|
.tooltip-arrow{position:absolute;width:0;height:0;}
|
||||||
|
.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;}
|
||||||
|
.popover.right{margin-left:5px;}
|
||||||
|
.popover.bottom{margin-top:5px;}
|
||||||
|
.popover.left{margin-left:-5px;}
|
||||||
|
.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
|
||||||
|
.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
|
||||||
|
.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
|
||||||
|
.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
|
||||||
|
.popover .arrow{position:absolute;width:0;height:0;}
|
||||||
|
.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);}
|
||||||
|
.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}
|
||||||
|
.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;}
|
||||||
|
.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";}
|
||||||
|
.thumbnails:after{clear:both;}
|
||||||
|
.thumbnails>li{float:left;margin:0 0 18px 20px;}
|
||||||
|
.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}
|
||||||
|
a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
|
||||||
|
.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
|
||||||
|
.thumbnail .caption{padding:9px;}
|
||||||
|
.label{padding:2px 4px 3px;font-size:11.049999999999999px;font-weight:bold;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
|
||||||
|
.label:hover{color:#ffffff;text-decoration:none;}
|
||||||
|
.label-important{background-color:#b94a48;}
|
||||||
|
.label-important:hover{background-color:#953b39;}
|
||||||
|
.label-warning{background-color:#f89406;}
|
||||||
|
.label-warning:hover{background-color:#c67605;}
|
||||||
|
.label-success{background-color:#468847;}
|
||||||
|
.label-success:hover{background-color:#356635;}
|
||||||
|
.label-info{background-color:#3a87ad;}
|
||||||
|
.label-info:hover{background-color:#2d6987;}
|
||||||
|
@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
|
||||||
|
.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
|
||||||
|
.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}
|
||||||
|
.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}
|
||||||
|
.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);}
|
||||||
|
.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
|
||||||
|
.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);}
|
||||||
|
.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
|
||||||
|
.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);}
|
||||||
|
.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
|
||||||
|
.accordion{margin-bottom:18px;}
|
||||||
|
.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
|
||||||
|
.accordion-heading{border-bottom:0;}
|
||||||
|
.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
|
||||||
|
.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
|
||||||
|
.carousel{position:relative;margin-bottom:18px;line-height:1;}
|
||||||
|
.carousel-inner{overflow:hidden;width:100%;position:relative;}
|
||||||
|
.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
|
||||||
|
.carousel .item>img{display:block;line-height:1;}
|
||||||
|
.carousel .active,.carousel .next,.carousel .prev{display:block;}
|
||||||
|
.carousel .active{left:0;}
|
||||||
|
.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;}
|
||||||
|
.carousel .next{left:100%;}
|
||||||
|
.carousel .prev{left:-100%;}
|
||||||
|
.carousel .next.left,.carousel .prev.right{left:0;}
|
||||||
|
.carousel .active.left{left:-100%;}
|
||||||
|
.carousel .active.right{left:100%;}
|
||||||
|
.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
|
||||||
|
.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
|
||||||
|
.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);}
|
||||||
|
.carousel-caption h4,.carousel-caption p{color:#ffffff;}
|
||||||
|
.hero-unit{padding:60px;margin-bottom:30px;background-color:#f5f5f5;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;}
|
||||||
|
.hero-unit p{font-size:18px;font-weight:200;line-height:27px;}
|
||||||
|
.pull-right{float:right;}
|
||||||
|
.pull-left{float:left;}
|
||||||
|
.hide{display:none;}
|
||||||
|
.show{display:block;}
|
||||||
|
.invisible{visibility:hidden;}
|
7
app/assets/stylesheets/mailr.css.sass
Normal file
7
app/assets/stylesheets/mailr.css.sass
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
body.simple
|
||||||
|
margin-top: 20px
|
||||||
|
margin-bottom: 20px
|
||||||
|
#footer-simple
|
||||||
|
text-align: center
|
||||||
|
.top-pix18
|
||||||
|
margin-top: 18px
|
96
app/controllers/application_controller.rb
Normal file → Executable file
96
app/controllers/application_controller.rb
Normal file → Executable file
|
@ -1,3 +1,99 @@
|
||||||
|
require 'yaml'
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
protect_from_forgery
|
protect_from_forgery
|
||||||
|
|
||||||
|
before_filter :load_settings,:current_user,:set_locale
|
||||||
|
#before_filter :plugins_configuration
|
||||||
|
|
||||||
|
def load_settings
|
||||||
|
$defaults ||= YAML::load(File.open(Rails.root.join('config','settings.yml')))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
################################# protected section ###########################################
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def theme_resolver
|
||||||
|
if @current_user.nil?
|
||||||
|
$defaults['theme']
|
||||||
|
else
|
||||||
|
@current_user.prefs.theme || $defaults['theme']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_locale
|
||||||
|
if @current_user.nil?
|
||||||
|
I18n.locale = $defaults['locale'] || I18n.default_locale
|
||||||
|
else
|
||||||
|
I18n.locale = @current_user.prefs.locale.to_sym || I18n.default_locale
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_user
|
||||||
|
@current_user ||= User.find(session[:user_id]) if session[:user_id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_current_user
|
||||||
|
if @current_user.nil?
|
||||||
|
session["return_to"] = request.fullpath
|
||||||
|
redirect_to :controller => 'user', :action => 'login'
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def selected_folder
|
||||||
|
if session[:selected_folder]
|
||||||
|
@selected_folder = session[:selected_folder]
|
||||||
|
else
|
||||||
|
folder = @current_user.folders.inbox.first
|
||||||
|
if not folder.nil?
|
||||||
|
@selected_folder = folder.full_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_current_folders
|
||||||
|
@folders_shown = @current_user.folders.shown.order("name asc")
|
||||||
|
if not @selected_folder.nil?
|
||||||
|
@current_folder = @current_user.folders.find_by_full_name(@selected_folder)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_compose_buttons
|
||||||
|
@buttons = []
|
||||||
|
@buttons << {:text => 'sendout',:scope=>:compose,:image => 'email.png'}
|
||||||
|
@buttons << {:text => 'save',:scope=>:compose,:image => 'save.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_message_with_params
|
||||||
|
@message = Message.new(params[:message])
|
||||||
|
# if params[:message]
|
||||||
|
# @message.update_attributes(params[:message])
|
||||||
|
# end
|
||||||
|
files = Dir.glob(File.join($defaults["msg_upload_dir"],@current_user.username + "*"))
|
||||||
|
@attachments = []
|
||||||
|
files.each do |f|
|
||||||
|
@attachments << {:name => File.basename(f).gsub!(/#{@current_user.username}_/,"") , :size => File.stat(f).size }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_system_folders
|
||||||
|
@drafts_folder = @current_user.folders.drafts.first
|
||||||
|
@sent_folder = @current_user.folders.sent.first
|
||||||
|
@inbox_folder = @current_user.folders.inbox.first
|
||||||
|
@trash_folder = @current_user.folders.trash.first
|
||||||
|
end
|
||||||
|
|
||||||
|
##################################### private section ##########################################
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def plugins_configuration
|
||||||
|
WillPaginate::ViewHelpers.pagination_options[:previous_label] = t(:previous_page,:scope=>:common)
|
||||||
|
WillPaginate::ViewHelpers.pagination_options[:next_label] = t(:next_page,:scope=>:common)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
135
app/controllers/contacts_controller.rb
Executable file
135
app/controllers/contacts_controller.rb
Executable file
|
@ -0,0 +1,135 @@
|
||||||
|
require 'tempfile'
|
||||||
|
|
||||||
|
class ContactsController < ApplicationController
|
||||||
|
|
||||||
|
before_filter :check_current_user,:selected_folder, :get_current_folders
|
||||||
|
|
||||||
|
before_filter :get_contacts, :only => [:index]
|
||||||
|
|
||||||
|
before_filter :prepare_ops_buttons, :prepare_export_import_buttons,:only => [:index]
|
||||||
|
|
||||||
|
#theme :theme_resolver
|
||||||
|
|
||||||
|
def index
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def ops
|
||||||
|
if params["create_new"]
|
||||||
|
redirect_to(new_contact_path)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if !params["cids"]
|
||||||
|
flash[:warning] = t(:no_selected,:scope=>:contact)
|
||||||
|
else
|
||||||
|
if params["delete_selected"]
|
||||||
|
params["cids"].each do |id|
|
||||||
|
@current_user.contacts.find_by_id(id).destroy
|
||||||
|
end
|
||||||
|
elsif params["compose_to_selected"]
|
||||||
|
redirect_to :controller=>'messages',:action=>'compose',:cids=>params["cids"]
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to(contacts_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
#problem http://binary10ve.blogspot.com/2011/05/migrating-to-rails-3-got-stuck-with.html
|
||||||
|
#def destroy
|
||||||
|
# @current_user.contacts.find(params[:id]).destroy
|
||||||
|
# redirect_to(contacts_path)
|
||||||
|
#end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@contact = Contact.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
@contact = @current_user.contacts.find(params[:id])
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@contact = @current_user.contacts.build(params[:contact])
|
||||||
|
if @contact.valid?
|
||||||
|
@contact.save
|
||||||
|
flash[:success] = t(:was_created,:scope=>:contact)
|
||||||
|
redirect_to(contacts_path)
|
||||||
|
else
|
||||||
|
render 'new'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@contact = @current_user.contacts.find(params[:id])
|
||||||
|
if @contact.update_attributes(params[:contact])
|
||||||
|
redirect_to(contacts_path)
|
||||||
|
else
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def external
|
||||||
|
if params["export"]
|
||||||
|
redirect_to :action => 'export'
|
||||||
|
return
|
||||||
|
elsif params["import"]
|
||||||
|
begin
|
||||||
|
raise t(:no_file_chosen,:scope=>:common) if not params[:upload]
|
||||||
|
raise t(:no_tmp_dir,:scope=>:common) if not File.exists?($defaults["msg_upload_dir"])
|
||||||
|
tmp_file = Tempfile.new($defaults["contact_tmp_filename"],$defaults["msg_upload_dir"])
|
||||||
|
tmp_file.write(params[:upload][:datafile].read)
|
||||||
|
tmp_file.flush
|
||||||
|
tmp_file.rewind
|
||||||
|
tmp_file.readlines.each do |line|
|
||||||
|
next if line =~ /^#/
|
||||||
|
Contact.import(@current_user,line)
|
||||||
|
end
|
||||||
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
|
flash[:error] = {:title => e.to_s,:info => e.record.inspect + e.record.errors.inspect}
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = e.to_s
|
||||||
|
else
|
||||||
|
flash[:success] = t(:were_imported,:scope=>:contact)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def export
|
||||||
|
contacts = @current_user.contacts
|
||||||
|
s = ""
|
||||||
|
contacts.each do |c|
|
||||||
|
s += c.export + "\r\n"
|
||||||
|
end
|
||||||
|
headers['Content-type'] = "text/csv"
|
||||||
|
headers['Content-Disposition'] = %(attachment; filename="contacts.csv")
|
||||||
|
render :text => s
|
||||||
|
end
|
||||||
|
|
||||||
|
####################################### protected section ################################
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def prepare_ops_buttons
|
||||||
|
@buttons = []
|
||||||
|
@buttons << {:text => 'compose_to_selected',:scope=> 'contact', :image => 'email.png'}
|
||||||
|
@buttons << {:text => 'create_new',:scope=> 'contact', :image => 'plus.png'}
|
||||||
|
@buttons << {:text => 'delete_selected',:scope=>'contact',:image => 'minus.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_export_import_buttons
|
||||||
|
@ei_buttons = []
|
||||||
|
@ei_buttons << {:text => 'import',:scope=>'contact',:image => 'right.png'}
|
||||||
|
@ei_buttons << {:text => 'export',:scope=>'contact',:image => 'left.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
####################################### private section ##################################
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_contacts
|
||||||
|
@contacts = Contact.getPageForUser(@current_user,params[:page],params[:sort_field],params[:sort_dir])
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
172
app/controllers/folders_controller.rb
Executable file
172
app/controllers/folders_controller.rb
Executable file
|
@ -0,0 +1,172 @@
|
||||||
|
require 'imap_mailbox'
|
||||||
|
require 'imap_session'
|
||||||
|
|
||||||
|
class FoldersController < ApplicationController
|
||||||
|
|
||||||
|
include ImapMailboxModule
|
||||||
|
include ImapSessionModule
|
||||||
|
|
||||||
|
before_filter :check_current_user,:selected_folder, :get_current_folders
|
||||||
|
|
||||||
|
before_filter :open_imap_session, :except => [:index,:show_hide,:system]
|
||||||
|
after_filter :close_imap_session, :except => [:index,:show_hide,:system]
|
||||||
|
|
||||||
|
before_filter :get_folders
|
||||||
|
before_filter :prepare_buttons_to_folders
|
||||||
|
|
||||||
|
#theme :theme_resolver
|
||||||
|
|
||||||
|
def index
|
||||||
|
#before_filter
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
if params[:folder][:target].empty?
|
||||||
|
flash[:warning] = t(:to_create_empty,:scope=>:folder)
|
||||||
|
render "index"
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
#TODO recreate local copy of folders
|
||||||
|
if params[:folder][:parent].empty?
|
||||||
|
@mailbox.create_folder(params[:folder][:target])
|
||||||
|
else
|
||||||
|
parent_folder = @current_user.folders.find(params[:folder][:parent])
|
||||||
|
if parent_folder.depth >= $defaults["mailbox_max_parent_folder_depth"].to_i
|
||||||
|
raise Exception, t(:max_depth,:scope=>:folder)
|
||||||
|
end
|
||||||
|
@mailbox.create_folder(parent_folder.full_name + parent_folder.delim + params[:folder][:target])
|
||||||
|
end
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = t(:can_not_create,:scope=>:folder) + ' (' + e.to_s + ')'
|
||||||
|
render 'index'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
flash[:success] = t(:was_created,:scope=>:folder)
|
||||||
|
redirect_to :action => 'index'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete
|
||||||
|
if params[:folder][:delete].empty?
|
||||||
|
flash[:warning] = t(:to_delete_empty,:scope=>:folder)
|
||||||
|
render "index"
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
folder = @current_user.folders.find(params[:folder][:delete])
|
||||||
|
if @folders_system.include?(folder)
|
||||||
|
raise Exception, t(:system,:scope=>:folder)
|
||||||
|
end
|
||||||
|
@mailbox.delete_folder(folder.full_name)
|
||||||
|
if @current_folder.eql? folder
|
||||||
|
session[:selected_folder] = nil
|
||||||
|
end
|
||||||
|
folder.destroy
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = t(:can_not_delete,:scope=>:folder) + ' (' + e.to_s + ')'
|
||||||
|
render 'index'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
flash[:success] = t(:was_deleted,:scope=>:folder)
|
||||||
|
redirect_to :action => 'index'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def system
|
||||||
|
logger.custom('sss',params[:folder].inspect)
|
||||||
|
@folders.each do |f|
|
||||||
|
logger.custom('s',f.inspect)
|
||||||
|
if f.isSystem?
|
||||||
|
f.setNone
|
||||||
|
end
|
||||||
|
if f.id == params[:folder][:mailbox_inbox].to_i
|
||||||
|
f.setInbox
|
||||||
|
end
|
||||||
|
if f.id == params[:folder][:mailbox_sent].to_i
|
||||||
|
f.setSent
|
||||||
|
end
|
||||||
|
if f.id == params[:folder][:mailbox_trash].to_i
|
||||||
|
f.setTrash
|
||||||
|
end
|
||||||
|
if f.id == params[:folder][:mailbox_drafts].to_i
|
||||||
|
f.setDrafts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def refresh
|
||||||
|
# TODO save system folders
|
||||||
|
if params[:refresh]
|
||||||
|
Folder.refresh(@mailbox,@current_user)
|
||||||
|
flash.keep
|
||||||
|
elsif params[:show_hide]
|
||||||
|
if !params["folders_to_show"].nil?
|
||||||
|
@folders.each do |f|
|
||||||
|
if params["folders_to_show"].include?(f.id.to_s)
|
||||||
|
f.shown = true
|
||||||
|
f.save
|
||||||
|
else
|
||||||
|
f.shown = false
|
||||||
|
f.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def select
|
||||||
|
session[:selected_folder] = params[:id]
|
||||||
|
redirect_to :controller => 'messages', :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def refresh_status
|
||||||
|
@folders_shown.each do |f|
|
||||||
|
@mailbox.set_folder(f.full_name)
|
||||||
|
folder_status = @mailbox.status
|
||||||
|
f.update_attributes(:total => folder_status['MESSAGES'], :unseen => folder_status['UNSEEN'])
|
||||||
|
end
|
||||||
|
redirect_to :controller=> 'messages', :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def emptybin
|
||||||
|
begin
|
||||||
|
trash_folder = @current_user.folders.trash.first
|
||||||
|
if trash_folder.nil?
|
||||||
|
raise Exception, t(:not_configured_trash,:scope=>:folder)
|
||||||
|
end
|
||||||
|
@mailbox.set_folder(trash_folder.full_name)
|
||||||
|
trash_folder.messages.each do |m|
|
||||||
|
@mailbox.delete_message(m.uid)
|
||||||
|
end
|
||||||
|
@mailbox.expunge
|
||||||
|
trash_folder.messages.destroy_all
|
||||||
|
trash_folder.update_attributes(:unseen => 0, :total => 0)
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = "#{t(:imap_error,:scope=>:common)} (#{e.to_s})"
|
||||||
|
end
|
||||||
|
redirect_to :controller => 'messages', :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
############################################# protected section #######################################
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def prepare_buttons_to_folders
|
||||||
|
@buttons = []
|
||||||
|
@buttons << {:text => 'show_hide',:scope=>'folder',:image => 'flag.png'}
|
||||||
|
@buttons << {:text => 'refresh',:scope=>'folder',:image => 'refresh.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_folders
|
||||||
|
@folders = @current_user.folders
|
||||||
|
@folders_shown = @current_user.folders.shown
|
||||||
|
#@folders_system = @current_user.folders.sys
|
||||||
|
@current_user.folders.inbox.first.nil? ? @folder_inbox = "" : @folder_inbox = @current_user.folders.inbox.first.id
|
||||||
|
@current_user.folders.drafts.first.nil? ? @folder_drafts = "" : @folder_drafts = @current_user.folders.drafts.first.id
|
||||||
|
@current_user.folders.sent.first.nil? ? @folder_sent = "" : @folder_sent = @current_user.folders.sent.first.id
|
||||||
|
@current_user.folders.trash.first.nil? ? @folder_trash = "" : @folder_trash = @current_user.folders.trash.first.id
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
53
app/controllers/internal_controller.rb
Executable file
53
app/controllers/internal_controller.rb
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
class InternalController < ApplicationController
|
||||||
|
|
||||||
|
before_filter :check_current_user ,:selected_folder, :get_current_folders, :only => [:about]
|
||||||
|
|
||||||
|
#theme :theme_resolver
|
||||||
|
layout "simple"
|
||||||
|
|
||||||
|
|
||||||
|
ERRORS = [
|
||||||
|
:internal_server_error,
|
||||||
|
:not_found,
|
||||||
|
:unprocessable_entity
|
||||||
|
].freeze
|
||||||
|
|
||||||
|
ERRORS.each do |e|
|
||||||
|
define_method e do
|
||||||
|
@title = t(e,:scope=>:internal)
|
||||||
|
@error = t(e,:scope=>:internal)
|
||||||
|
render 'error'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def error
|
||||||
|
@title = t(:unspecified_error,:scope=>:internal)
|
||||||
|
@error = params[:error] || t(:unspecified_error,:scope=>:internal)
|
||||||
|
end
|
||||||
|
|
||||||
|
def imaperror
|
||||||
|
@title = t(:imap_error,:scope => :internal)
|
||||||
|
@error = params[:error] || t(:unspecified_error, :scope => :internal)
|
||||||
|
logger.error "!!! InternalControllerImapError: " + @error
|
||||||
|
render 'error'
|
||||||
|
end
|
||||||
|
|
||||||
|
def loginfailure
|
||||||
|
reset_session
|
||||||
|
flash[:error] = t(:login_failure,:scope=>:user)
|
||||||
|
@current_user = nil
|
||||||
|
redirect_to :controller=>'user', :action => 'login'
|
||||||
|
end
|
||||||
|
|
||||||
|
def onlycanlogins
|
||||||
|
reset_session
|
||||||
|
flash[:error] = t(:only_can_logins,:scope=>:user)
|
||||||
|
@current_user = nil
|
||||||
|
redirect_to :controller=>'user', :action => 'login'
|
||||||
|
end
|
||||||
|
|
||||||
|
def about
|
||||||
|
render 'internal/about', :layout => 'application'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
133
app/controllers/links_controller.rb
Executable file
133
app/controllers/links_controller.rb
Executable file
|
@ -0,0 +1,133 @@
|
||||||
|
require 'tempfile'
|
||||||
|
|
||||||
|
class LinksController < ApplicationController
|
||||||
|
|
||||||
|
before_filter :check_current_user,:selected_folder, :get_current_folders
|
||||||
|
|
||||||
|
before_filter :get_links, :only => [:index]
|
||||||
|
|
||||||
|
before_filter :prepare_ops_buttons, :only => [:index]
|
||||||
|
|
||||||
|
#, :prepare_export_import_buttons,:only => [:index]
|
||||||
|
|
||||||
|
#theme :theme_resolver
|
||||||
|
|
||||||
|
def index
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def ops
|
||||||
|
if params["create_new"]
|
||||||
|
redirect_to(new_link_path)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if !params["ids"]
|
||||||
|
flash[:warning] = t(:no_selected,:scope=>:link)
|
||||||
|
else
|
||||||
|
if params["delete_selected"]
|
||||||
|
params["ids"].each do |id|
|
||||||
|
@current_user.links.find_by_id(id).destroy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to(links_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
#problem http://binary10ve.blogspot.com/2011/05/migrating-to-rails-3-got-stuck-with.html
|
||||||
|
#def destroy
|
||||||
|
# @current_user.contacts.find(params[:id]).destroy
|
||||||
|
# redirect_to(contacts_path)
|
||||||
|
#end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@link = Link.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
@link = @current_user.links.find(params[:id])
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@link = @current_user.links.build(params[:link])
|
||||||
|
if @link.valid?
|
||||||
|
@link.save
|
||||||
|
flash[:success] = t(:was_created,:scope=>:link)
|
||||||
|
redirect_to(links_path)
|
||||||
|
else
|
||||||
|
render 'new'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@link = @current_user.links.find(params[:id])
|
||||||
|
if @link.update_attributes(params[:link])
|
||||||
|
redirect_to(links_path)
|
||||||
|
else
|
||||||
|
render 'edit'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def external
|
||||||
|
if params["export"]
|
||||||
|
redirect_to :action => 'export'
|
||||||
|
return
|
||||||
|
elsif params["import"]
|
||||||
|
begin
|
||||||
|
raise t(:no_file_chosen,:scope=>:common) if not params[:upload]
|
||||||
|
raise t(:no_tmp_dir,:scope=>:common) if not File.exists?($defaults["msg_upload_dir"])
|
||||||
|
tmp_file = Tempfile.new($defaults["contact_tmp_filename"],$defaults["msg_upload_dir"])
|
||||||
|
tmp_file.write(params[:upload][:datafile].read)
|
||||||
|
tmp_file.flush
|
||||||
|
tmp_file.rewind
|
||||||
|
tmp_file.readlines.each do |line|
|
||||||
|
next if line =~ /^#/
|
||||||
|
Contact.import(@current_user,line)
|
||||||
|
end
|
||||||
|
rescue ActiveRecord::RecordInvalid => e
|
||||||
|
flash[:error] = {:title => e.to_s,:info => e.record.inspect + e.record.errors.inspect}
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = e.to_s
|
||||||
|
else
|
||||||
|
flash[:success] = t(:were_imported,:scope=>:contact)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
def export
|
||||||
|
contacts = @current_user.contacts
|
||||||
|
s = ""
|
||||||
|
contacts.each do |c|
|
||||||
|
s += c.export + "\r\n"
|
||||||
|
end
|
||||||
|
headers['Content-type'] = "text/csv"
|
||||||
|
headers['Content-Disposition'] = %(attachment; filename="contacts.csv")
|
||||||
|
render :text => s
|
||||||
|
end
|
||||||
|
|
||||||
|
####################################### protected section ################################
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def prepare_ops_buttons
|
||||||
|
@buttons = []
|
||||||
|
@buttons << {:text => 'create_new',:scope=> 'link', :image => 'plus.png'}
|
||||||
|
@buttons << {:text => 'delete_selected',:scope=>'link',:image => 'minus.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_export_import_buttons
|
||||||
|
@ei_buttons = []
|
||||||
|
@ei_buttons << {:text => 'import',:scope=>'link',:image => 'right.png'}
|
||||||
|
@ei_buttons << {:text => 'export',:scope=>'link',:image => 'left.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
####################################### private section ##################################
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def get_links
|
||||||
|
@links = Link.getPageForUser(@current_user,params[:page],params[:sort_field],params[:sort_dir])
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
210
app/controllers/messages_controller.rb
Executable file
210
app/controllers/messages_controller.rb
Executable file
|
@ -0,0 +1,210 @@
|
||||||
|
require 'imap_session'
|
||||||
|
require 'imap_mailbox'
|
||||||
|
require 'imap_message'
|
||||||
|
require 'mail'
|
||||||
|
require 'mail_plugin_extension'
|
||||||
|
|
||||||
|
class MessagesController < ApplicationController
|
||||||
|
|
||||||
|
include ImapMailboxModule
|
||||||
|
include ImapSessionModule
|
||||||
|
include ImapMessageModule
|
||||||
|
include MessagesHelper
|
||||||
|
|
||||||
|
before_filter :check_current_user ,:selected_folder,:get_current_folders
|
||||||
|
before_filter :open_imap_session, :select_imap_folder
|
||||||
|
before_filter :prepare_compose_buttons, :only => [:compose]
|
||||||
|
before_filter :get_system_folders, :only => [:index]
|
||||||
|
before_filter :create_message_with_params, :only => [:compose]
|
||||||
|
before_filter :prepare_multi1_buttons, :only => [:index,:show]
|
||||||
|
before_filter :prepare_multi2_buttons, :only => [:index]
|
||||||
|
before_filter :prepare_multi3_buttons, :only => [:show]
|
||||||
|
after_filter :close_imap_session
|
||||||
|
|
||||||
|
#theme :theme_resolver
|
||||||
|
|
||||||
|
def index
|
||||||
|
|
||||||
|
if @sent_folder.nil? || @drafts_folder.nil? || @inbox_folder.nil? || @trash_folder.nil?
|
||||||
|
flash[:warning] = t(:not_all_configured,:scope => :folder)
|
||||||
|
end
|
||||||
|
|
||||||
|
if @current_folder.nil?
|
||||||
|
flash[:warning] = t(:no_selected,:scope => :folder)
|
||||||
|
redirect_to :controller => 'folders', :action => 'index'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
@messages = []
|
||||||
|
|
||||||
|
folder_status = @mailbox.status
|
||||||
|
@current_folder.update_attributes(:total => folder_status['MESSAGES'], :unseen => folder_status['UNSEEN'])
|
||||||
|
|
||||||
|
folder_status['MESSAGES'].zero? ? uids_remote = [] : uids_remote = @mailbox.fetch_uids
|
||||||
|
uids_local = @current_user.messages.where(:folder_id => @current_folder).collect(&:uid)
|
||||||
|
|
||||||
|
logger.custom('current_folder',@current_folder.inspect)
|
||||||
|
logger.custom('uids_local',uids_local.join(","))
|
||||||
|
logger.custom('uids_remote',uids_remote.join(","))
|
||||||
|
logger.custom('to_delete',(uids_local-uids_remote).join(","))
|
||||||
|
logger.custom('to_fetch',(uids_remote-uids_local).join(","))
|
||||||
|
|
||||||
|
(uids_local-uids_remote).each do |uid|
|
||||||
|
@current_folder.messages.find_by_uid(uid).destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
(uids_remote-uids_local).each_slice($defaults["imap_fetch_slice"].to_i) do |slice|
|
||||||
|
messages = @mailbox.uid_fetch(slice, ImapMessageModule::IMAPMessage.fetch_attr)
|
||||||
|
messages.each do |m|
|
||||||
|
Message.createForUser(@current_user,@current_folder,m)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@messages = Message.getPageForUser(@current_user,@current_folder,params[:page],params[:sort_field],params[:sort_dir])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def compose
|
||||||
|
#before filter :prepare_compose_buttons, :create_message_with_params
|
||||||
|
@operation = :new
|
||||||
|
if params["cid"].present?
|
||||||
|
contact = @current_user.contacts.find_by_id(params["cid"])
|
||||||
|
if not contact.nil?
|
||||||
|
@message.to_addr = contact.email
|
||||||
|
end
|
||||||
|
elsif params["cids"].present?
|
||||||
|
contacts = []
|
||||||
|
params["cids"].each do |c|
|
||||||
|
contact = @current_user.contacts.find_by_id(c)
|
||||||
|
if not contact.nil?
|
||||||
|
contacts << contact.email
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@message.to_addr = contacts.join(';')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@images = []
|
||||||
|
@attachments = []
|
||||||
|
@text_part = nil
|
||||||
|
@html_part = nil
|
||||||
|
|
||||||
|
@message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:id]).first
|
||||||
|
@message.update_attributes(:unseen => false)
|
||||||
|
imap_message = @mailbox.fetch_body(@message.uid)
|
||||||
|
|
||||||
|
mail = Mail.new(imap_message)
|
||||||
|
@plain_header = mail.header.to_s
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME missing fields and support arrays
|
||||||
|
#@from = mail.From.addrs.presence
|
||||||
|
#@to = mail.To.addrs.presence
|
||||||
|
@from = @message.from_addr
|
||||||
|
@to = @message.to_addr
|
||||||
|
@cc = mail.Cc.presence
|
||||||
|
@bcc = mail.Bcc.presence
|
||||||
|
#@subject = mail.Subject
|
||||||
|
@date = mail.date.presence
|
||||||
|
|
||||||
|
if mail.multipart? == true
|
||||||
|
if not mail.text_part.nil?
|
||||||
|
@text_part = mail.text_part.decoded_and_charseted
|
||||||
|
end
|
||||||
|
if not mail.html_part.nil?
|
||||||
|
@html_part = mail.html_part.decoded_and_charseted
|
||||||
|
end
|
||||||
|
attachments = mail.attachments
|
||||||
|
if not attachments.size.zero?
|
||||||
|
for idx in 0..attachments.size - 1
|
||||||
|
a = attachments[idx]
|
||||||
|
a.idx = idx
|
||||||
|
a.parent_id = @message.uid
|
||||||
|
if a.isImage? and @current_user.prefs.msg_image_view_as.to_sym.eql?(:thumbnail)
|
||||||
|
@images << a
|
||||||
|
else
|
||||||
|
@attachments << a
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
part = Mail::Part.new(mail)
|
||||||
|
part.idx = 0
|
||||||
|
part.parent_id = @message.uid
|
||||||
|
if part.isText?
|
||||||
|
@text_part = part.decoded_and_charseted
|
||||||
|
elsif part.isImage? and @current_user.prefs.msg_image_view_as.to_sym.eql?(:thumbnail)
|
||||||
|
@images << part
|
||||||
|
elsif part.isHtml?
|
||||||
|
@html_part = part.decoded_and_charseted
|
||||||
|
else
|
||||||
|
@attachments << part
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def html_body
|
||||||
|
message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:id]).first
|
||||||
|
mail = Mail.new(@mailbox.fetch_body(message.uid))
|
||||||
|
if mail.multipart?
|
||||||
|
@body = mail.html_part.decoded_and_charseted
|
||||||
|
else
|
||||||
|
@body = mail.decoded_and_charseted
|
||||||
|
end
|
||||||
|
|
||||||
|
if @body.nil?
|
||||||
|
@body = t(:no_body,:scope=>:message)
|
||||||
|
else
|
||||||
|
if @body=~/cid:([\w@\.]+)/
|
||||||
|
attachments = mail.attachments
|
||||||
|
if not attachments.size.zero?
|
||||||
|
for idx in 0..attachments.size - 1
|
||||||
|
@body.gsub!(/cid:#{attachments[idx].cid}/,attachment_download_path(message.uid,idx))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
render 'html_body',:layout => 'html_body'
|
||||||
|
end
|
||||||
|
|
||||||
|
def attachment
|
||||||
|
attachments = []
|
||||||
|
message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:id]).first
|
||||||
|
mail = Mail.new(@mailbox.fetch_body(message.uid))
|
||||||
|
if mail.multipart? == true
|
||||||
|
attachments = mail.attachments
|
||||||
|
else
|
||||||
|
attachments << Mail::Part.new(mail)
|
||||||
|
end
|
||||||
|
a = attachments[params[:idx].to_i]
|
||||||
|
headers['Content-type'] = a.main_type + "/" + a.sub_type
|
||||||
|
headers['Content-Disposition'] = %(attachment; filename="#{a.filename}")
|
||||||
|
render :text => a.decoded
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
############################################# protected section ##########################################
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def prepare_multi2_buttons
|
||||||
|
@multi2_buttons = []
|
||||||
|
@multi2_buttons << {:text => 'trash',:scope=>:message,:image => 'trash.png'}
|
||||||
|
@multi2_buttons << {:text => 'set_unread',:scope=>:message,:image => 'unseen.png'}
|
||||||
|
@multi2_buttons << {:text => 'set_read',:scope=>:message,:image => 'seen.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_multi1_buttons
|
||||||
|
@multi1_buttons = []
|
||||||
|
@multi1_buttons << {:text => 'copy',:scope=>:message,:image => 'copy.png'}
|
||||||
|
@multi1_buttons << {:text => 'move',:scope=>:message,:image => 'move.png'}
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_multi3_buttons
|
||||||
|
@multi3_buttons = []
|
||||||
|
@multi3_buttons << {:text => 'show_header',:scope=>:show,:image => 'zoom.png'}
|
||||||
|
@multi3_buttons << {:text => 'trash',:scope=>:show,:image => 'trash.png'}
|
||||||
|
@multi3_buttons << {:text => 'reply',:scope=>:show,:image => 'reply.png'}
|
||||||
|
end
|
||||||
|
end
|
354
app/controllers/messages_ops_controller.rb
Executable file
354
app/controllers/messages_ops_controller.rb
Executable file
|
@ -0,0 +1,354 @@
|
||||||
|
require 'imap_session'
|
||||||
|
require 'imap_mailbox'
|
||||||
|
require 'imap_message'
|
||||||
|
require 'mail'
|
||||||
|
require 'mail_plugin_extension'
|
||||||
|
require 'net/smtp'
|
||||||
|
|
||||||
|
class MessagesOpsController < ApplicationController
|
||||||
|
|
||||||
|
include ImapMailboxModule
|
||||||
|
include ImapSessionModule
|
||||||
|
include ImapMessageModule
|
||||||
|
include MessagesHelper
|
||||||
|
|
||||||
|
before_filter :check_current_user ,:selected_folder,:get_current_folders
|
||||||
|
before_filter :open_imap_session, :select_imap_folder
|
||||||
|
before_filter :prepare_compose_buttons
|
||||||
|
before_filter :get_system_folders, :only => [:composed,:single,:multi]
|
||||||
|
before_filter :prepare_composed , :only => [:composed]
|
||||||
|
before_filter :create_message_with_params, :only=> [:composed,:single,:multi]
|
||||||
|
after_filter :close_imap_session
|
||||||
|
#theme :theme_resolver
|
||||||
|
|
||||||
|
|
||||||
|
############################################### single #####################################
|
||||||
|
|
||||||
|
def single
|
||||||
|
if params[:reply]
|
||||||
|
reply
|
||||||
|
return
|
||||||
|
elsif params[:trash]
|
||||||
|
trash
|
||||||
|
elsif params[:move]
|
||||||
|
move
|
||||||
|
elsif params[:copy]
|
||||||
|
copy
|
||||||
|
end
|
||||||
|
redirect_to :controller => 'messages', :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
############################################### multi ######################################
|
||||||
|
|
||||||
|
def multi
|
||||||
|
begin
|
||||||
|
if !params[:uids]
|
||||||
|
flash[:warning] = t(:no_selected,:scope=>:message)
|
||||||
|
elsif params[:set_unread]
|
||||||
|
set_unread
|
||||||
|
elsif params[:set_read]
|
||||||
|
set_read
|
||||||
|
elsif params[:trash]
|
||||||
|
trash
|
||||||
|
elsif params[:copy]
|
||||||
|
copy
|
||||||
|
elsif params[:move]
|
||||||
|
move
|
||||||
|
end
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = "#{t(:imap_error,:scope=>:internal)} (#{e.to_s})"
|
||||||
|
end
|
||||||
|
redirect_to :controller => 'messages', :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
############################################### ################################################
|
||||||
|
|
||||||
|
|
||||||
|
def set_unread
|
||||||
|
params["uids"].each do |uid|
|
||||||
|
@mailbox.set_unread(uid)
|
||||||
|
@current_user.messages.where('folder_id = ? and uid = ?',@current_folder,uid).first.update_attributes(:unseen => 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_read
|
||||||
|
params["uids"].each do |uid|
|
||||||
|
@mailbox.set_read(uid)
|
||||||
|
@current_user.messages.where('folder_id = ? and uid = ?',@current_folder,uid).first.update_attributes(:unseen => 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def trash
|
||||||
|
if @trash_folder.nil?
|
||||||
|
flash[:warning] = t(:not_configured_trash, :scope=>:folder)
|
||||||
|
else
|
||||||
|
params["uids"].each do |uid|
|
||||||
|
@mailbox.move_message(uid,@trash_folder.full_name)
|
||||||
|
message = @current_folder.messages.find_by_uid(uid)
|
||||||
|
message.change_folder(@trash_folder)
|
||||||
|
end
|
||||||
|
@mailbox.expunge
|
||||||
|
@trash_folder.update_stats
|
||||||
|
@current_folder.update_stats
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy
|
||||||
|
if params[:folder][:target].empty?
|
||||||
|
flash[:warning] = t(:no_selected,:scope=>:folder)
|
||||||
|
else
|
||||||
|
dest_folder = @current_user.folders.find(params[:folder][:target])
|
||||||
|
params["uids"].each do |uid|
|
||||||
|
@mailbox.copy_message(uid,dest_folder.full_name)
|
||||||
|
message = @current_folder.messages.find_by_uid(uid)
|
||||||
|
new_message = message.clone
|
||||||
|
new_message.folder_id = dest_folder.id
|
||||||
|
new_message.save
|
||||||
|
end
|
||||||
|
dest_folder.update_stats
|
||||||
|
@current_folder.update_stats
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def move
|
||||||
|
if params[:folder][:target].empty?
|
||||||
|
flash[:warning] = t(:no_selected,:scope=>:folder)
|
||||||
|
else
|
||||||
|
dest_folder = @current_user.folders.find(params[:folder][:target])
|
||||||
|
logger.info "DEST: "+dest_folder.inspect
|
||||||
|
params["uids"].each do |uid|
|
||||||
|
logger.info "UID: "+uid
|
||||||
|
logger.info "DEST_FULL: "+dest_folder.full_name
|
||||||
|
@mailbox.move_message(uid,dest_folder.full_name)
|
||||||
|
message = @current_folder.messages.find_by_uid(uid)
|
||||||
|
logger.info "M: "+message.inspect
|
||||||
|
logger.info "UPDATE_DEST_BEFORE1: "+dest_folder.inspect
|
||||||
|
message.change_folder(dest_folder)
|
||||||
|
logger.info "UPDATE_DEST_BEFORE2: "+dest_folder.inspect
|
||||||
|
end
|
||||||
|
logger.info "UPDATE_DEST_BEFORE: "+dest_folder.inspect
|
||||||
|
@mailbox.expunge
|
||||||
|
dest_folder.update_stats
|
||||||
|
logger.info "UPDATE_DEST: "+dest_folder.inspect
|
||||||
|
@current_folder.update_stats
|
||||||
|
logger.info "UPDATE_CUT: "+@current_folder.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload
|
||||||
|
begin
|
||||||
|
raise MailrException.new :cause=>:no_tmp_dir,:scope=>:common if not File.exists?($defaults["msg_upload_dir"])
|
||||||
|
raise MailrException.new :cause=>:no_file_chosen,:scope=>:common if not params[:upload]
|
||||||
|
@operation = :upload
|
||||||
|
name = params[:file][:data].original_filename
|
||||||
|
upload_dir = $defaults["msg_upload_dir"]
|
||||||
|
path = File.join(upload_dir, @current_user.username + "_" + name)
|
||||||
|
File.open(path, "wb") { |f| f.write(params[:file][:data].read) }
|
||||||
|
rescue MailrException => e
|
||||||
|
flash[:error] = t(e.message[:cause],:scope => e.message[:scope])
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = t(:general_error,:scope=>:internal) + " (" + e.class.name + " " + e.to_s + ")"
|
||||||
|
end
|
||||||
|
create_message_with_params
|
||||||
|
render 'messages/compose'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Files uploaded from Internet Explorer:
|
||||||
|
#
|
||||||
|
#Internet Explorer includes the entire path of a file in the filename sent, so the original_filename routine will return something like:
|
||||||
|
#
|
||||||
|
#C:\Documents and Files\user_name\Pictures\My File.jpg
|
||||||
|
#
|
||||||
|
#instead of just:
|
||||||
|
#
|
||||||
|
#My File.jpg
|
||||||
|
#
|
||||||
|
#This is easily handled by File.basename, which strips out everything before the filename.
|
||||||
|
#
|
||||||
|
#def sanitize_filename(file_name)
|
||||||
|
# # get only the filename, not the whole path (from IE)
|
||||||
|
# just_filename = File.basename(file_name)
|
||||||
|
# # replace all none alphanumeric, underscore or perioids
|
||||||
|
# # with underscore
|
||||||
|
# just_filename.sub(/[^\w\.\-]/,'_')
|
||||||
|
#end
|
||||||
|
#
|
||||||
|
#Deleting an existing File:
|
||||||
|
#
|
||||||
|
#If you want to delete any existing file then its simple and need to write following code:
|
||||||
|
#
|
||||||
|
# def cleanup
|
||||||
|
# File.delete("#{RAILS_ROOT}/dirname/#{@filename}")
|
||||||
|
# if File.exist?("#{RAILS_ROOT}/dirname/#{@filename}")
|
||||||
|
# end
|
||||||
|
|
||||||
|
def composed
|
||||||
|
if params[:delete_marked] and params[:files]
|
||||||
|
params[:files].each do |filename|
|
||||||
|
path = File.join(Rails.root,$defaults["msg_upload_dir"],@current_user.username + "_" +filename)
|
||||||
|
File.delete(path) if File.exist?(path)
|
||||||
|
end
|
||||||
|
create_message_with_params
|
||||||
|
@operation = :new
|
||||||
|
render 'messages/compose'
|
||||||
|
return
|
||||||
|
elsif params[:upload]
|
||||||
|
upload
|
||||||
|
elsif params[:save]
|
||||||
|
save
|
||||||
|
elsif params[:sendout]
|
||||||
|
sendout
|
||||||
|
else
|
||||||
|
redirect_to :controller => 'messages', :action => 'index'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def sendout
|
||||||
|
begin
|
||||||
|
smtp_server = @current_user.servers.primary_for_smtp
|
||||||
|
raise MailrException.new :cause=>:not_configured_smtp,:scope => :compose if smtp_server.nil?
|
||||||
|
raise MailrException.new :cause=>:has_no_domain,:scope=>:user if @current_user.has_domain?.nil?
|
||||||
|
raise MailrException.new :cause=>:not_configured_sent,:scope=>:compose if @sent_folder.nil?
|
||||||
|
send_mail_message( smtp_server,
|
||||||
|
@current_user.has_domain?,
|
||||||
|
@current_user.login,
|
||||||
|
@current_user.get_cached_password(session),
|
||||||
|
@mail.to_s,
|
||||||
|
@current_user.email,
|
||||||
|
params[:message][:to_addr]
|
||||||
|
)
|
||||||
|
@mailbox.append(@sent_folder.full_name,@mail.to_s,[:Seen])
|
||||||
|
upload_dir = $defaults["msg_upload_dir"]
|
||||||
|
@attachments.each do |file|
|
||||||
|
path = File.join(upload_dir, @current_user.username + "_" + file[:name])
|
||||||
|
File.delete(path) if File.exist?(path)
|
||||||
|
end
|
||||||
|
rescue MailrException => e
|
||||||
|
flash[:error] = t(e.message[:cause],:scope => e.message[:scope])
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = t(:general_error,:scope=>:internal) + " (" + e.class.name + " " + e.to_s + ")"
|
||||||
|
else
|
||||||
|
flash[:success] = t(:was_sent,:scope => :compose)
|
||||||
|
redirect_to :controller => 'messages', :action => 'index'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
@operation = :new
|
||||||
|
render 'messages/compose'
|
||||||
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
begin
|
||||||
|
raise MailrException.new :cause=>:not_configured_drafts,:scope=>:folder if @drafts_folder.nil?
|
||||||
|
@mailbox.append(@drafts_folder.full_name,@mail.to_s,[:Seen])
|
||||||
|
if params[:olduid].present?
|
||||||
|
@mailbox.move_message(params[:olduid],@trash_folder.full_name)
|
||||||
|
@mailbox.expunge
|
||||||
|
end
|
||||||
|
rescue MailrException => e
|
||||||
|
flash[:error] = t(e.message[:cause],:scope => e.message[:scope])
|
||||||
|
rescue Exception => e
|
||||||
|
flash[:error] = t(:general_error,:scope=>:internal) + " (" + e.class.name + " " + e.to_s + ")"
|
||||||
|
else
|
||||||
|
@attachments.each do |filename|
|
||||||
|
path = File.join(Rails.root,filename)
|
||||||
|
File.delete(path) if File.exist?(path)
|
||||||
|
end
|
||||||
|
flash[:success] = t(:was_saved,:scope => :compose)
|
||||||
|
end
|
||||||
|
redirect_to :controller => 'messages', :action => 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
#FIXME edit does not support attachments
|
||||||
|
def edit
|
||||||
|
old_message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:uids].first).first
|
||||||
|
@message = Message.new
|
||||||
|
@message.to_addr = old_message.to_addr
|
||||||
|
@message.subject = old_message.subject
|
||||||
|
|
||||||
|
imap_message = @mailbox.fetch_body(old_message.uid)
|
||||||
|
mail = Mail.new(imap_message)
|
||||||
|
if mail.multipart?
|
||||||
|
@message.body = mail.text_part.nil? ? "" : mail.text_part.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
|
||||||
|
else
|
||||||
|
@message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
|
||||||
|
end
|
||||||
|
@attachments = []
|
||||||
|
@operation = :edit
|
||||||
|
@olduid = old_message.uid
|
||||||
|
render 'messages/compose'
|
||||||
|
end
|
||||||
|
|
||||||
|
def reply
|
||||||
|
old_message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:uids].first).first
|
||||||
|
@message = Message.new
|
||||||
|
@message.to_addr = old_message.from_addr
|
||||||
|
@message.subject = old_message.subject
|
||||||
|
|
||||||
|
imap_message = @mailbox.fetch_body(old_message.uid)
|
||||||
|
mail = Mail.new(imap_message)
|
||||||
|
if mail.multipart?
|
||||||
|
@message.body = mail.text_part.nil? ? "" : mail.text_part.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
|
||||||
|
else
|
||||||
|
@message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
|
||||||
|
end
|
||||||
|
@attachments = []
|
||||||
|
@operation = :reply
|
||||||
|
render 'messages/compose'
|
||||||
|
end
|
||||||
|
###################################### protected section #######################################
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def send_mail_message(smtp_server,domain,username,password,msgstr,from,to)
|
||||||
|
if smtp_server.auth.nil?
|
||||||
|
smtp = Net::SMTP.start(smtp_server.name, smtp_server.port, domain)
|
||||||
|
else
|
||||||
|
smtp = Net::SMTP.start(smtp_server.name, smtp_server.port, domain, username, password, smtp_server.auth)
|
||||||
|
end
|
||||||
|
smtp.send_message msgstr, from, to
|
||||||
|
smtp.finish
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_composed
|
||||||
|
@mail = Mail.new
|
||||||
|
@mail.subject = params[:message][:subject]
|
||||||
|
@mail.from = @current_user.full_id
|
||||||
|
#TODO check if email address is valid if not get address from contacts
|
||||||
|
@mail.to = params[:message][:to_addr]
|
||||||
|
@mail.body = params[:message][:body]
|
||||||
|
@attachments = Dir.glob(File.join($defaults["msg_upload_dir"],@current_user.username + "*"))
|
||||||
|
@attachments.each do |a|
|
||||||
|
@mail.add_file :filename => File.basename(a.gsub(/#{@current_user.username}_/,"")), :content => File.read(a)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
############################################ set_mail_defaults ####################################
|
||||||
|
|
||||||
|
def set_mail_defaults(user,server,session)
|
||||||
|
if server.auth.nil? or server.auth == 'none'
|
||||||
|
password = nil
|
||||||
|
authentication = nil
|
||||||
|
enable_starttls_auto = nil
|
||||||
|
openssl_verify_mode = nil
|
||||||
|
user_name = nil
|
||||||
|
else
|
||||||
|
password = user.get_cached_password(session)
|
||||||
|
authentication = server.auth
|
||||||
|
enable_starttls_auto = server.use_tls
|
||||||
|
openssl_verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||||
|
user_name = user.login
|
||||||
|
end
|
||||||
|
Mail.defaults do
|
||||||
|
delivery_method :smtp, {:address => server.name,
|
||||||
|
:port => server.port,
|
||||||
|
:domain => user.domain,
|
||||||
|
:user_name => user_name,
|
||||||
|
:password => password,
|
||||||
|
:authentication => authentication,
|
||||||
|
:enable_starttls_auto => enable_starttls_auto,
|
||||||
|
:openssl_verify_mode => openssl_verify_mode
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
55
app/controllers/prefs_controller.rb
Executable file
55
app/controllers/prefs_controller.rb
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
class PrefsController < ApplicationController
|
||||||
|
|
||||||
|
before_filter :check_current_user,:selected_folder
|
||||||
|
|
||||||
|
before_filter :get_current_folders
|
||||||
|
|
||||||
|
before_filter :get_prefs, :only => [:look,:update_look]
|
||||||
|
|
||||||
|
#theme :theme_resolver
|
||||||
|
|
||||||
|
def update_look
|
||||||
|
if params[:prefs]
|
||||||
|
@prefs.update_attributes(params[:prefs])
|
||||||
|
end
|
||||||
|
flash[:success] = t(:were_saved,:scope=>:prefs)
|
||||||
|
redirect_to :action => 'look'
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_servers
|
||||||
|
|
||||||
|
redirect_to :action => 'servers'
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_identity
|
||||||
|
if params[:user]
|
||||||
|
@current_user.first_name = params[:user][:first_name]
|
||||||
|
@current_user.last_name = params[:user][:last_name]
|
||||||
|
@current_user.domain = params[:user][:domain]
|
||||||
|
if @current_user.valid?
|
||||||
|
@current_user.save
|
||||||
|
flash[:success] = t(:were_saved,:scope=>:prefs)
|
||||||
|
redirect_to :action => 'identity'
|
||||||
|
else
|
||||||
|
render 'prefs/identity'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def look
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def identity
|
||||||
|
end
|
||||||
|
|
||||||
|
def servers
|
||||||
|
@servers = @current_user.servers
|
||||||
|
end
|
||||||
|
|
||||||
|
############################# protected section ##################################
|
||||||
|
|
||||||
|
def get_prefs
|
||||||
|
@prefs = @current_user.prefs
|
||||||
|
end
|
||||||
|
end
|
75
app/controllers/user_controller.rb
Executable file
75
app/controllers/user_controller.rb
Executable file
|
@ -0,0 +1,75 @@
|
||||||
|
class UserController < ApplicationController
|
||||||
|
|
||||||
|
#theme :theme_resolver
|
||||||
|
layout "simple"
|
||||||
|
|
||||||
|
def login
|
||||||
|
end
|
||||||
|
|
||||||
|
def logout
|
||||||
|
reset_session
|
||||||
|
flash[:success] = t(:logged_out,:scope=>:user)
|
||||||
|
redirect_to :action => "login"
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate
|
||||||
|
|
||||||
|
if not $defaults["only_can_logins"].nil?
|
||||||
|
if not $defaults["only_can_logins"].include?(params[:user][:login])
|
||||||
|
redirect_to :controller => 'internal', :action => 'onlycanlogins'
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
user = User.find_by_login(params[:user][:login])
|
||||||
|
if user.nil?
|
||||||
|
redirect_to :action => 'unknown' ,:login=> params[:user][:login]
|
||||||
|
else
|
||||||
|
session[:user_id] = user.id
|
||||||
|
user.set_cached_password(session,params[:user][:password])
|
||||||
|
|
||||||
|
if session["return_to"]
|
||||||
|
redirect_to(session["return_to"])
|
||||||
|
session["return_to"] = nil
|
||||||
|
else
|
||||||
|
redirect_to :controller=> 'messages', :action=> 'index'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def loginfailure
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@user = User.new
|
||||||
|
@server = Server.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def unknown
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
|
||||||
|
@user = User.new
|
||||||
|
@user.login = params[:user][:login]
|
||||||
|
@user.first_name = params[:user][:first_name]
|
||||||
|
@user.last_name = params[:user][:last_name]
|
||||||
|
|
||||||
|
@server = Server.new
|
||||||
|
@server.name = params[:server][:name]
|
||||||
|
|
||||||
|
if @user.valid? and @server.valid?
|
||||||
|
@user.save
|
||||||
|
#@server.user_id = @user.id
|
||||||
|
#@server.save
|
||||||
|
Prefs.create_default(@user)
|
||||||
|
Server.create_defaults(@user)
|
||||||
|
flash[:success] = t(:setup_done,:scope=>:user)
|
||||||
|
redirect_to :action => 'login'
|
||||||
|
else
|
||||||
|
render "setup"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
332
app/helpers/application_helper.rb
Normal file → Executable file
332
app/helpers/application_helper.rb
Normal file → Executable file
|
@ -1,2 +1,334 @@
|
||||||
|
require 'iconv'
|
||||||
|
|
||||||
module ApplicationHelper
|
module ApplicationHelper
|
||||||
|
|
||||||
|
def form_field(object,field,flabel,example,val)
|
||||||
|
model_name = eval(object.class.model_name)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"param_group\">"
|
||||||
|
if not object.errors[field.to_sym].empty?
|
||||||
|
html << "<div class=\"fieldWithErrors\">"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
html << "<label class=\"label\">"
|
||||||
|
flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym)
|
||||||
|
html << "</label>"
|
||||||
|
|
||||||
|
if not object.errors[field.to_sym].empty?
|
||||||
|
html << "<span class=\"error\"> "
|
||||||
|
html << object.errors[field.to_sym].to_s
|
||||||
|
html << "</span>"
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
html << "<input id=\""
|
||||||
|
html << object.class.name.downcase+"_"+field
|
||||||
|
html << "\""
|
||||||
|
html << " name=\"#{object.class.name.downcase}[#{field}]\""
|
||||||
|
html << " type=\"text\" class=\"text_field\" value=\""
|
||||||
|
value = val || object.instance_eval(field) || ""
|
||||||
|
html << value
|
||||||
|
html << "\"/>"
|
||||||
|
html << "<span class=\"description\">"
|
||||||
|
html << t(:example,:scope=>:common)
|
||||||
|
html << ": "
|
||||||
|
html << example
|
||||||
|
html << "</span>"
|
||||||
|
html << "</div>"
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_param_view(object,field,value)
|
||||||
|
model_name = eval(object.class.model_name)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"group clearfix\">"
|
||||||
|
html << "<label class=\"label\">#{model_name.human_attribute_name(field)}: </label>"
|
||||||
|
html << value
|
||||||
|
html << "</div>"
|
||||||
|
html
|
||||||
|
end
|
||||||
|
|
||||||
|
def area_field(object,field,flabel,example,val,cols,rows)
|
||||||
|
model_name = eval(object.class.model_name)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"group\">"
|
||||||
|
|
||||||
|
if not object.errors[field.to_sym].empty?
|
||||||
|
html << "<div class=\"fieldWithErrors\">"
|
||||||
|
end
|
||||||
|
|
||||||
|
html << "<label class=\"label\">"
|
||||||
|
flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym)
|
||||||
|
html << "</label>"
|
||||||
|
|
||||||
|
if not object.errors[field.to_sym].empty?
|
||||||
|
html << "<span class=\"error\">"
|
||||||
|
html << object.errors[field.to_sym].to_s
|
||||||
|
html << "</span>"
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
name = object.class.name.downcase + '[' + field + ']'
|
||||||
|
id = object.class.name.downcase+"_"+field
|
||||||
|
value = val || object.instance_eval(field) || ""
|
||||||
|
html << "<textarea id=\"#{id}\" name=\"#{name}\" class=\"text_area\" cols=\"#{cols}\" rows=\"#{rows}\">#{value}</textarea>"
|
||||||
|
|
||||||
|
desc = t(:example,:scope=>:common) + ": " + example
|
||||||
|
html << "<span class=\"description\">#{desc}</span>"
|
||||||
|
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_button(text,image)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"group\">"
|
||||||
|
html << "<button class=\"button\" type=\"submit\">"
|
||||||
|
html << "<img src=\""
|
||||||
|
html << current_theme_image_path(image)
|
||||||
|
html << "\" alt=\""
|
||||||
|
html << t(text.to_sym)
|
||||||
|
html << "\" />"
|
||||||
|
html << t(text.to_sym)
|
||||||
|
html << "</button></div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def single_action(text,scope,image)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"actiongroup clearfix\">"
|
||||||
|
html << "<button class=\"button\" name=\"#{text}\" type=\"submit\">"
|
||||||
|
html << "<img src=\""
|
||||||
|
html << current_theme_image_path(image)
|
||||||
|
html << "\" alt=\""
|
||||||
|
html << t(text.to_sym, :scope => scope.to_sym)
|
||||||
|
html << "\" />"
|
||||||
|
html << t(text.to_sym, :scope => scope.to_sym)
|
||||||
|
html << "</button></div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def single_action_onclick(text,scope,image,onclick)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"actiongroup clearfix\">"
|
||||||
|
html << "<button class=\"button\" type=\"submit\" onclick=\"window.location='"
|
||||||
|
html << onclick
|
||||||
|
html << "'\">"
|
||||||
|
html << "<img src=\""
|
||||||
|
html << current_theme_image_path(image)
|
||||||
|
html << "\" alt=\""
|
||||||
|
html << t(text.to_sym, :scope => scope.to_sym)
|
||||||
|
html << "\" />"
|
||||||
|
html << t(text.to_sym, :scope => scope.to_sym)
|
||||||
|
html << "</button>"
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_action(buttons)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"actiongroup clearfix\">"
|
||||||
|
buttons.each do |b|
|
||||||
|
html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
|
||||||
|
html << "<img src=\""
|
||||||
|
html << current_theme_image_path(b[:image])
|
||||||
|
html << "\" alt=\""
|
||||||
|
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
|
||||||
|
html << "\" />"
|
||||||
|
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
|
||||||
|
html << "</button> "
|
||||||
|
end
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_action_text(buttons,text)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"group\">"
|
||||||
|
buttons.each do |b|
|
||||||
|
html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
|
||||||
|
html << "<img src=\""
|
||||||
|
html << current_theme_image_path(b[:image])
|
||||||
|
html << "\" alt=\""
|
||||||
|
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
|
||||||
|
html << "\" />"
|
||||||
|
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
|
||||||
|
html << "</button> "
|
||||||
|
end
|
||||||
|
html << text
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_buttons(buttons)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"group\">"
|
||||||
|
|
||||||
|
buttons.each do |b|
|
||||||
|
html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
|
||||||
|
html << "<img src=\""
|
||||||
|
html << current_theme_image_path(b[:image])
|
||||||
|
html << "\" alt=\""
|
||||||
|
html << t(b[:text].to_sym)
|
||||||
|
html << "\" />"
|
||||||
|
html << t(b[:text].to_sym)
|
||||||
|
html << "</button> "
|
||||||
|
end
|
||||||
|
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def form_button_value(text,image,onclick)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"group\">"
|
||||||
|
html << "<button class=\"button\" type=\"submit\" onclick=\"window.location='"
|
||||||
|
html << onclick
|
||||||
|
html << "'\">"
|
||||||
|
html << "<img src=\""
|
||||||
|
html << current_theme_image_path(image)
|
||||||
|
html << "\" alt=\""
|
||||||
|
html << text
|
||||||
|
html << "\" />"
|
||||||
|
html << t(text.to_sym)
|
||||||
|
html << "</button></div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def simple_input_field(name,id,label,value)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"param_group\">"
|
||||||
|
html << "<label class=\"label\">#{label}</label>"
|
||||||
|
html << "<input name=\"#{name}[#{id}]\" id=\"#{name}_#{id} class=\"text_field\" type=\"text\" value=\"#{value}\">"
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_field(name,object,label,blank)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"group\">"
|
||||||
|
html << "<label class=\"label\">#{label}</label>"
|
||||||
|
html << select(name, name, object.all.collect {|p| [ p.name, p.id ] }, { :include_blank => (blank == true ? true : false)})
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_field_table(object,field,table_choices,choice,blank)
|
||||||
|
model_name = eval(object.class.model_name)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"param_group\">"
|
||||||
|
html << "<label class=\"label\">#{model_name.human_attribute_name(field)}</label>"
|
||||||
|
html << select(object.class.to_s.downcase, field, options_for_select(table_choices,choice), {:include_blank => blank})
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_field_table_t(object,field,table_choices,choice,blank)
|
||||||
|
model_name = eval(object.class.model_name)
|
||||||
|
html = ""
|
||||||
|
html << "<div class=\"param_group\">"
|
||||||
|
html << "<label class=\"label\">#{model_name.human_attribute_name(field)}</label>"
|
||||||
|
t = []
|
||||||
|
table_choices.each do |c|
|
||||||
|
t << [t(c.to_sym,:scope=>:prefs),c.to_s]
|
||||||
|
end
|
||||||
|
html << select(object.class.to_s.downcase, field, options_for_select(t,choice), {:include_blank => blank})
|
||||||
|
html << "</div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
#def form_simle_field(name,label,value)
|
||||||
|
# html = ""
|
||||||
|
# html << "<div class=\"group\">"
|
||||||
|
# html << "<label class=\"label\">#{label}</label>"
|
||||||
|
# html << "<input class=\"text_field\" type=\"text\" value=\"#{value}\">"
|
||||||
|
# html << "</div>"
|
||||||
|
#end
|
||||||
|
|
||||||
|
#def nav_to_folders
|
||||||
|
# link_to( t(:folders,:scope=>:folder), :controller=>:folders, :action=>:index )
|
||||||
|
#end
|
||||||
|
#
|
||||||
|
#def nav_to_messages
|
||||||
|
# link_to( t(:messages,:scope=>:message), :controller=>:messages, :action=>:index )
|
||||||
|
#end
|
||||||
|
#
|
||||||
|
#def nav_to_compose
|
||||||
|
# link_to( t(:compose,:scope=>:compose), :controller=>:messages, :action=>:compose )
|
||||||
|
#end
|
||||||
|
#
|
||||||
|
#def nav_to_contacts
|
||||||
|
# link_to( t(:contacts,:scope=>:contact), contacts_path )
|
||||||
|
#end
|
||||||
|
#
|
||||||
|
#def nav_to_prefs
|
||||||
|
# link_to( t(:prefs,:scope=>:prefs), prefs_look_path )
|
||||||
|
#end
|
||||||
|
|
||||||
|
def single_navigation(label,scope)
|
||||||
|
s = ""
|
||||||
|
s += "<ul>"
|
||||||
|
s += "<li class=\"first active\">#{link_to(t(label,:scope=>scope),'#')}</li>"
|
||||||
|
s += "<li class=\"last\"> </li>"
|
||||||
|
s += "</ul>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def main_navigation(active)
|
||||||
|
instance_variable_set("@#{active}", "active")
|
||||||
|
s = ""
|
||||||
|
s += "<ul>"
|
||||||
|
s += "<li class=\"first #{@messages_tab}\">#{link_to( t(:messages,:scope=>:message), messages_path )}</li>"
|
||||||
|
s += "<li class=\"#{@compose_tab}\">#{link_to( t(:compose,:scope=>:compose), compose_path )}</li>"
|
||||||
|
s += "<li class=\"#{@folders_tab}\">#{link_to( t(:folders,:scope=>:folder), folders_path )}</li>"
|
||||||
|
s += "<li class=\"#{@contacts_tab}\">#{link_to( t(:contacts,:scope=>:contact), contacts_path )}</li>"
|
||||||
|
s += "<li class=\"#{@prefs_tab}\">#{link_to( t(:prefs,:scope=>:prefs), prefs_look_path )}</li>"
|
||||||
|
s += "<li class=\"last #{@links_tab}\">#{link_to( t(:links,:scope=>:link), links_path )}</li>"
|
||||||
|
s += "</ul>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def prefs_navigation(active)
|
||||||
|
instance_variable_set("@#{active}", "active")
|
||||||
|
s = ""
|
||||||
|
s += "<ul>"
|
||||||
|
s += "<li class=\"first #{@look_tab}\">#{link_to( t(:look,:scope=>:prefs), prefs_look_path )}</li>"
|
||||||
|
s += "<li class=\"#{@identity_tab}\">#{link_to( t(:identity,:scope=>:prefs), prefs_identity_path )}</li>"
|
||||||
|
s += "<li class=\"last #{@servers_tab}\">#{link_to( t(:servers,:scope=>:prefs), prefs_servers_path )}</li>"
|
||||||
|
s += "</ul>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def multi_select(id, name, objects, selected_objects, label, value,joiner,content = {})
|
||||||
|
options = ""
|
||||||
|
objects.each do |o|
|
||||||
|
selected = selected_objects.include?(o) ? " selected=\"selected\"" : ""
|
||||||
|
option_value = escape_once(o.send(value))
|
||||||
|
text = [option_value]
|
||||||
|
unless content[:text].nil?
|
||||||
|
text = []
|
||||||
|
content[:text].each do |t|
|
||||||
|
text << o.send(t)
|
||||||
|
end
|
||||||
|
text = text.join(joiner)
|
||||||
|
end
|
||||||
|
text.gsub!(/^\./,'')
|
||||||
|
bracket = []
|
||||||
|
unless content[:bracket].nil?
|
||||||
|
content[:bracket].each do |b|
|
||||||
|
bracket << o.send(b)
|
||||||
|
end
|
||||||
|
bracket = bracket.join(joiner)
|
||||||
|
end
|
||||||
|
option_content = bracket.empty? ? "#{text}" : "#{text} (#{bracket})"
|
||||||
|
options << "<option value=\"#{option_value}\"#{selected}> #{option_content} </option>\n"
|
||||||
|
end
|
||||||
|
"<div class=\"param_group\"><label class=\"label\">#{label}</label><select multiple=\"multiple\" size=10 id=\"#{id}\" name=\"#{name}\">\n#{options}</select></div>"
|
||||||
|
end
|
||||||
|
|
||||||
|
def force_charset(text)
|
||||||
|
begin
|
||||||
|
Iconv.iconv("UTF-8",$defaults["msg_unknown_charset"],text)
|
||||||
|
rescue
|
||||||
|
text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_for_sidebar
|
||||||
|
s = render :partial => 'sidebar/logo'
|
||||||
|
s += render :partial => 'folders/list'
|
||||||
|
s += render :partial => 'sidebar/calendar_view'
|
||||||
|
s += render :partial => 'internal/version'
|
||||||
|
s
|
||||||
|
end
|
||||||
|
|
||||||
|
def boolean_answer(answer)
|
||||||
|
answer == true ? t(:true_answer,:scope=>:common) : t(:false_answer,:scope=>:common)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
54
app/models/contact.rb
Executable file
54
app/models/contact.rb
Executable file
|
@ -0,0 +1,54 @@
|
||||||
|
class Contact < ActiveRecord::Base
|
||||||
|
|
||||||
|
validates_length_of :nick, :within => 5..15
|
||||||
|
validates_length_of :first_name,:last_name, :within => 3..20
|
||||||
|
validates_length_of :email, :within => 5..50
|
||||||
|
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
|
||||||
|
validates_length_of :info, :maximum => 100
|
||||||
|
validate :check_unique_nick, :on => :create
|
||||||
|
default_scope :order => 'nick ASC'
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
|
||||||
|
def self.getPageForUser(user,page,sort_field,sort_dir)
|
||||||
|
|
||||||
|
if sort_field
|
||||||
|
if Contact.attribute_method?(sort_field) == true
|
||||||
|
order = sort_field
|
||||||
|
sort_dir == 'desc' ? order += ' desc' : sort_dir
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Contact.paginate :page => page , :per_page => $defaults["contacts_per_page"], :conditions=> ['user_id = ?', user.id],:order => order
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_name
|
||||||
|
first_name + ' ' + last_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_unique_nick
|
||||||
|
if !Contact.where('upper(nick) = ? and user_id = ?',nick.upcase,user_id).size.zero?
|
||||||
|
errors.add(:nick, :not_unique)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def export
|
||||||
|
fields = []
|
||||||
|
fields << nick.presence || ""
|
||||||
|
fields << first_name || ""
|
||||||
|
fields << last_name || ""
|
||||||
|
fields << email || ""
|
||||||
|
fields << info || ""
|
||||||
|
fields.join(';')
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.import(user,line)
|
||||||
|
fields = line.split(/;/)
|
||||||
|
contact = user.contacts.build( :nick => fields[0].strip,
|
||||||
|
:first_name => fields[1].strip,
|
||||||
|
:last_name => fields[2].strip,
|
||||||
|
:email => fields[3].strip,
|
||||||
|
:info => fields[4].strip)
|
||||||
|
contact.save!
|
||||||
|
end
|
||||||
|
end
|
146
app/models/folder.rb
Executable file
146
app/models/folder.rb
Executable file
|
@ -0,0 +1,146 @@
|
||||||
|
class Folder < ActiveRecord::Base
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
validates_presence_of :name, :on => :create
|
||||||
|
before_save :check_fill_params, :on => :create
|
||||||
|
has_many :messages, :dependent => :destroy
|
||||||
|
|
||||||
|
SYS_NONE = 0
|
||||||
|
SYS_TRASH = 1
|
||||||
|
SYS_INBOX = 2
|
||||||
|
SYS_SENT = 3
|
||||||
|
SYS_DRAFTS = 4
|
||||||
|
|
||||||
|
default_scope :order => 'name asc'
|
||||||
|
scope :shown, where(['shown = ?',true])
|
||||||
|
scope :inbox, where(['sys = ?',SYS_INBOX])
|
||||||
|
scope :sent, where(['sys = ?',SYS_SENT])
|
||||||
|
scope :drafts, where(['sys = ?',SYS_DRAFTS])
|
||||||
|
scope :trash, where(['sys = ?',SYS_TRASH])
|
||||||
|
scope :sys, where(['sys > ?',SYS_NONE])
|
||||||
|
|
||||||
|
def full_name
|
||||||
|
if parent.empty?
|
||||||
|
name
|
||||||
|
else
|
||||||
|
parent + delim + name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def depth
|
||||||
|
parent.split('.').size
|
||||||
|
end
|
||||||
|
|
||||||
|
def selected?(session_folder)
|
||||||
|
fields = session_folder.split("#")
|
||||||
|
fields[1].nil? ? fields.insert(0,"") : fields
|
||||||
|
(fields[1].downcase == name.downcase) && (fields[0].downcase == parent.downcase)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_stats
|
||||||
|
logger.info "MESS_BEFORE: "+messages.inspect
|
||||||
|
unseen = messages.where(:unseen => true).count
|
||||||
|
total = messages.count
|
||||||
|
logger.info "MESS: "+messages.inspect
|
||||||
|
logger.info "MESS: #{unseen} #{total}"
|
||||||
|
update_attributes(:unseen => unseen, :total => total)
|
||||||
|
end
|
||||||
|
|
||||||
|
def hasFullName?(folder_name)
|
||||||
|
full_name.downcase == folder_name.downcase
|
||||||
|
end
|
||||||
|
|
||||||
|
def isSystem?
|
||||||
|
sys > SYS_NONE
|
||||||
|
end
|
||||||
|
|
||||||
|
def isTrash?
|
||||||
|
sys == SYS_TRASH
|
||||||
|
end
|
||||||
|
|
||||||
|
def isSent?
|
||||||
|
sys == SYS_SENT
|
||||||
|
end
|
||||||
|
|
||||||
|
def isInbox?
|
||||||
|
sys == SYS_INBOX
|
||||||
|
end
|
||||||
|
|
||||||
|
def isDrafts?
|
||||||
|
sys == SYS_DRAFTS
|
||||||
|
end
|
||||||
|
|
||||||
|
def setNone
|
||||||
|
update_attributes(:sys => SYS_NONE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setTrash
|
||||||
|
update_attributes(:sys => SYS_TRASH)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setSent
|
||||||
|
update_attributes(:sys => SYS_SENT)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setInbox
|
||||||
|
update_attributes(:sys => SYS_INBOX)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setDrafts
|
||||||
|
update_attributes(:sys => SYS_DRAFTS)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############################################## private section #####################################
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_fill_params
|
||||||
|
self.total.nil? ? self.total = 0 : self.total
|
||||||
|
self.unseen.nil? ? self.unseen = 0 : self.unseen
|
||||||
|
self.parent.nil? ? self.parent = "" : self.parent
|
||||||
|
self.haschildren.nil? ? self.haschildren = false : self.haschildren
|
||||||
|
self.delim.nil? ? self.delim = "." : self.delim
|
||||||
|
self.sys.nil? ? self.sys = SYS_NONE : self.sys
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.createBulk(user,imapFolders)
|
||||||
|
imapFolders.each do |name,data|
|
||||||
|
data.attribs.find_index(:Haschildren).nil? ? has_children = 0 : has_children = 1
|
||||||
|
name_fields = name.split(data.delim)
|
||||||
|
|
||||||
|
if name_fields.count > 1
|
||||||
|
name = name_fields.delete_at(name_fields.size - 1)
|
||||||
|
parent = name_fields.join(data.delim)
|
||||||
|
else
|
||||||
|
name = name_fields[0]
|
||||||
|
parent = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
user.folders.create(
|
||||||
|
:name => name,
|
||||||
|
:parent => parent,
|
||||||
|
:haschildren => has_children,
|
||||||
|
:delim => data.delim,
|
||||||
|
:total => data.messages,
|
||||||
|
:unseen => data.unseen,
|
||||||
|
:sys => SYS_NONE)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find_by_full_name(data)
|
||||||
|
folder = data.gsub(/\./,'#')
|
||||||
|
fields = folder.split("#")
|
||||||
|
nam = fields.delete_at(fields.size - 1)
|
||||||
|
fields.size.zero? == true ? par = "" : par = fields.join(".")
|
||||||
|
where(['name = ? and parent = ?',nam,par]).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.refresh(mailbox,user)
|
||||||
|
user.folders.destroy_all
|
||||||
|
folders=mailbox.folders
|
||||||
|
Folder.createBulk(user,folders)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
19
app/models/link.rb
Normal file
19
app/models/link.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
class Link < ActiveRecord::Base
|
||||||
|
validates_length_of :name, :within => 5..30
|
||||||
|
validates_length_of :url, :within => 5..150
|
||||||
|
validates_length_of :info, :maximum => 50
|
||||||
|
belongs_to :user
|
||||||
|
default_scope :order => 'name asc'
|
||||||
|
|
||||||
|
def self.getPageForUser(user,page,sort_field,sort_dir)
|
||||||
|
|
||||||
|
if sort_field
|
||||||
|
if Link.attribute_method?(sort_field) == true
|
||||||
|
order = sort_field
|
||||||
|
sort_dir == 'desc' ? order += ' desc' : sort_dir
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Link.paginate :page => page , :per_page => $defaults["links_per_page"], :conditions=> ['user_id = ?', user.id],:order => order
|
||||||
|
end
|
||||||
|
end
|
73
app/models/message.rb
Executable file
73
app/models/message.rb
Executable file
|
@ -0,0 +1,73 @@
|
||||||
|
require 'iconv'
|
||||||
|
require 'mail'
|
||||||
|
|
||||||
|
class Message < ActiveRecord::Base
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :folder
|
||||||
|
|
||||||
|
#set_primary_key :uid
|
||||||
|
self.primary_key = :uid
|
||||||
|
attr_accessible :unseen, :to_addr, :size, :content_type, :folder_id, :subject, :date, :uid, :from_addr, :user_id, :msg_id, :body,:cc_addr,:bcc_addr
|
||||||
|
attr_accessor :body
|
||||||
|
|
||||||
|
def self.addr_to_db(addr)
|
||||||
|
ret = ""
|
||||||
|
name = addr.name
|
||||||
|
name.nil? ? ret : ret << ApplicationController.decode_quoted(name)
|
||||||
|
ret << "<" + addr.mailbox + "@" + addr.host
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.getPageForUser(user,folder,page,sort_field,sort_dir)
|
||||||
|
|
||||||
|
order = 'date desc'
|
||||||
|
if sort_field
|
||||||
|
if Message.attribute_method?(sort_field) == true
|
||||||
|
order = sort_field
|
||||||
|
sort_dir == 'desc' ? order += ' desc' : sort_dir
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Message.paginate :page => page , :per_page => user.prefs.msgs_per_page.to_i, :conditions=> ['user_id = ? and folder_id = ?', user.id,folder.id],:order => order
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.createForUser(user,folder,message)
|
||||||
|
|
||||||
|
# envelope = imap_message.attr['ENVELOPE']
|
||||||
|
#
|
||||||
|
# envelope.from.nil? ? from = "" : from = addr_to_db(envelope.from[0])
|
||||||
|
# envelope.to.nil? ? to = "" : to = addr_to_db(envelope.to[0])
|
||||||
|
# envelope.subject.nil? ? subject = "" : subject = ApplicationController.decode_quoted(envelope.subject)
|
||||||
|
|
||||||
|
mail = Mail.new(message.attr['RFC822.HEADER'])
|
||||||
|
|
||||||
|
mail.date.nil? ? date = nil : date = mail.date.to_s
|
||||||
|
mail.From.nil? ? from = nil : from = mail.From.charseted
|
||||||
|
mail.To.nil? ? to = nil : to = mail.To.charseted
|
||||||
|
mail.Subject.nil? ? subject = nil : subject = mail.Subject.charseted
|
||||||
|
|
||||||
|
#logger.custom('subject',mail.Subject.encoded)
|
||||||
|
#logger.custom('subject',subject)
|
||||||
|
#logger.custom('mail',mail.inspect)
|
||||||
|
|
||||||
|
create(
|
||||||
|
:user_id => user.id,
|
||||||
|
:folder_id => folder.id,
|
||||||
|
:msg_id => mail.message_id,
|
||||||
|
:uid => message.attr['UID'].to_i,
|
||||||
|
:from_addr => from,
|
||||||
|
:to_addr => to,
|
||||||
|
:subject => subject,
|
||||||
|
:content_type => mail.content_type,
|
||||||
|
:date => date,
|
||||||
|
:unseen => !(message.attr['FLAGS'].member? :Seen),
|
||||||
|
:size => message.attr['RFC822.SIZE']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_folder(folder)
|
||||||
|
update_attributes(:folder_id => folder.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
19
app/models/prefs.rb
Executable file
19
app/models/prefs.rb
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
class Prefs < ActiveRecord::Base
|
||||||
|
|
||||||
|
validates_presence_of :theme,:locale
|
||||||
|
|
||||||
|
has_one :user
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def self.create_default(user)
|
||||||
|
Prefs.create(:user_id => user.id,
|
||||||
|
:theme => $defaults['theme'],
|
||||||
|
:locale => $defaults['locale'],
|
||||||
|
:msgs_per_page => $defaults['msgs_per_page'],
|
||||||
|
:msg_send_type => $defaults['msg_send_type']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# TODO move refresh to prefs and make refresh page with messages
|
41
app/models/server.rb
Executable file
41
app/models/server.rb
Executable file
|
@ -0,0 +1,41 @@
|
||||||
|
class Server < ActiveRecord::Base
|
||||||
|
|
||||||
|
validates_presence_of :name
|
||||||
|
belongs_to :user
|
||||||
|
#before_save :fill_params
|
||||||
|
|
||||||
|
def self.primary_for_imap
|
||||||
|
where(:for_imap=>true).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.primary_for_smtp
|
||||||
|
where(:for_smtp=>true).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create_defaults(user)
|
||||||
|
create( :user_id=>user.id,
|
||||||
|
:name=>"localhost",
|
||||||
|
:port=>$defaults['imap_port'],
|
||||||
|
:use_ssl=>false,
|
||||||
|
:use_tls=>false,
|
||||||
|
:for_smtp=>false,
|
||||||
|
:for_imap=>true
|
||||||
|
)
|
||||||
|
create( :user_id=>user.id,
|
||||||
|
:name=>"localhost",
|
||||||
|
:port=>$defaults['smtp_port'],
|
||||||
|
:use_ssl=>false,
|
||||||
|
:use_tls=>false,
|
||||||
|
:for_smtp=>true,
|
||||||
|
:for_imap=>false
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
# private
|
||||||
|
|
||||||
|
# def fill_params
|
||||||
|
# port.nil? ? port = $defaults['imap_port'] : port
|
||||||
|
# $defaults['imap_use_ssl'] == true ? self.use_ssl = 1 : self.use_ssl = 0
|
||||||
|
# end
|
||||||
|
|
||||||
|
end
|
64
app/models/user.rb
Executable file
64
app/models/user.rb
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
require 'ezcrypto'
|
||||||
|
|
||||||
|
class User < ActiveRecord::Base
|
||||||
|
|
||||||
|
#acts_as_notes_owner
|
||||||
|
|
||||||
|
validates_presence_of :first_name,:last_name
|
||||||
|
validates_uniqueness_of :login
|
||||||
|
has_many :servers, :dependent => :destroy
|
||||||
|
has_one :prefs, :dependent => :destroy
|
||||||
|
has_many :folders, :dependent => :destroy
|
||||||
|
has_many :messages, :dependent => :destroy
|
||||||
|
has_many :contacts, :dependent => :destroy
|
||||||
|
has_many :links, :dependent => :destroy
|
||||||
|
|
||||||
|
def set_cached_password(session,password)
|
||||||
|
if $defaults['session_encryption']
|
||||||
|
session[:session_salt] = generate_salt
|
||||||
|
session[:user_password] = EzCrypto::Key.encrypt_with_password($defaults['session_password'], session[:session_salt], password)
|
||||||
|
else
|
||||||
|
session[:user_password] = password
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_cached_password(session)
|
||||||
|
if $defaults['session_encryption']
|
||||||
|
EzCrypto::Key.decrypt_with_password($defaults['session_password'], session[:session_salt], session[:user_password])
|
||||||
|
else
|
||||||
|
session[:user_password]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_salt
|
||||||
|
(0...8).map{65.+(rand(25)).chr}.join
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
first_name + " " + last_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def full_id
|
||||||
|
(name + " <" + email + ">") if email
|
||||||
|
end
|
||||||
|
|
||||||
|
def email
|
||||||
|
if login =~ /\@/
|
||||||
|
login
|
||||||
|
else
|
||||||
|
(login + "@" + domain) if domain.presence
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def username
|
||||||
|
login.gsub(/\@/,"_").gsub(/\./,"_")
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_domain?
|
||||||
|
return domain if domain.presence
|
||||||
|
if login =~ /\@/
|
||||||
|
login.split(/\@/)[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
38
app/views/layouts/application.html.erb
Normal file → Executable file
38
app/views/layouts/application.html.erb
Normal file → Executable file
|
@ -1,14 +1,36 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html
|
||||||
<html>
|
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||||
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Mailr</title>
|
<title>
|
||||||
<%= stylesheet_link_tag "application", :media => "all" %>
|
<%= t(:mailr,:scope=>:common) %>
|
||||||
<%= javascript_include_tag "application" %>
|
<%= yield :title %>
|
||||||
<%= csrf_meta_tags %>
|
</title>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
|
|
||||||
|
<%=stylesheet_link_tag current_theme_stylesheet_path('olive') %>
|
||||||
|
<%=stylesheet_link_tag current_theme_stylesheet_path('calendar_olive') %>
|
||||||
|
<%=stylesheet_link_tag current_theme_stylesheet_path('jquery-ui-dialog') %>
|
||||||
|
<%=stylesheet_link_tag current_theme_stylesheet_path('jquery-ui-custom') %>
|
||||||
|
|
||||||
|
<%=javascript_include_tag current_theme_javascript_path('jquery') %>
|
||||||
|
<%=javascript_include_tag current_theme_javascript_path('jquery-ui') %>
|
||||||
|
<%=javascript_include_tag current_theme_javascript_path('rails') %>
|
||||||
|
<%=javascript_include_tag current_theme_javascript_path('application') %>
|
||||||
|
|
||||||
|
<link rel="icon" type="image/x-icon" href="/favicon.ico"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div id="container">
|
||||||
|
<div id="sidebar">
|
||||||
|
<%= yield :sidebar %>
|
||||||
|
</div>
|
||||||
|
<div id="main">
|
||||||
|
<%= render :partial=>'layouts/flash', :object => flash %>
|
||||||
|
<%= calendar_window(:title=>t(:calendar,:scope=>:common)) %>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
1
app/views/layouts/html_body.erb
Executable file
1
app/views/layouts/html_body.erb
Executable file
|
@ -0,0 +1 @@
|
||||||
|
<%= yield %>
|
32
app/views/layouts/simple.html.haml
Executable file
32
app/views/layouts/simple.html.haml
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
!!!
|
||||||
|
%html
|
||||||
|
%head
|
||||||
|
%title
|
||||||
|
=t(:mailr,:scope=>:common)
|
||||||
|
= yield :title
|
||||||
|
= stylesheet_link_tag "application", :media => "all"
|
||||||
|
= javascript_include_tag "application"
|
||||||
|
= csrf_meta_tags
|
||||||
|
%body{:class=>"simple"}
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.span6.offset3
|
||||||
|
.row
|
||||||
|
%a{:href=>"/"}
|
||||||
|
= image_tag "logo.png"
|
||||||
|
.row
|
||||||
|
%hr/
|
||||||
|
- if flash[:error]
|
||||||
|
.alert.alert-error
|
||||||
|
= flash[:error]
|
||||||
|
- elsif flash[:info]
|
||||||
|
.alert.alert-info
|
||||||
|
= flash[:info]
|
||||||
|
- elsif flash[:success]
|
||||||
|
.alert.alert-success
|
||||||
|
= flash[:success]
|
||||||
|
= yield
|
||||||
|
.row
|
||||||
|
#footer-simple
|
||||||
|
%a{:href=>"https://github.com/musashimm/mailr"} MailR
|
||||||
|
\- open source web mail client
|
18
app/views/user/login.html.haml
Normal file
18
app/views/user/login.html.haml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
%form{:class=>"form-horizontal top-pix18",:action=>"#{url_for(:controller => 'user', :action => 'authenticate')}",:method=>"post"}
|
||||||
|
%fieldset
|
||||||
|
.control-group
|
||||||
|
%label{:class=>"control-label",:for=>"login"}
|
||||||
|
= User.human_attribute_name('login')
|
||||||
|
.controls
|
||||||
|
%input{:id=>"user_login",:name=>"user[login]"}
|
||||||
|
.control-group
|
||||||
|
%label{:class=>"control-label",:for=>"password"}
|
||||||
|
= User.human_attribute_name('password')
|
||||||
|
.controls
|
||||||
|
%input{:id=>"user_password",:name=>"user[password]"}
|
||||||
|
.control-group
|
||||||
|
.controls
|
||||||
|
%button{:class=>"btn btn-primary",:type=>"submit"}
|
||||||
|
= t(:please_login,:scope=>:user)
|
||||||
|
|
||||||
|
|
20
app/views/user/setup.html.erb
Executable file
20
app/views/user/setup.html.erb
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
<% content_for :title do %>
|
||||||
|
<%= t(:setup,:scope=>:user) %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<div class="box2">
|
||||||
|
<div class="logo"><a href="/"><img src="<%= current_theme_image_path('logo_small.png')%>" alt="<%= t(:mailr,:scope=>:common) %>"/></a>
|
||||||
|
</div>
|
||||||
|
<h2><%= t(:setup,:scope=>:user) %></h2>
|
||||||
|
<div class="content">
|
||||||
|
<form action="<%=url_for(:controller => 'user', :action => 'create')%>" method="post" class="form">
|
||||||
|
<%= raw form_field(@user,"login",nil,"joe.doe",params[:user].nil? ? params[:login] : params[:user][:login]) %>
|
||||||
|
<%= raw form_field(@user,"first_name",nil,"Joe","") %>
|
||||||
|
<%= raw form_field(@user,"last_name",nil,"Doe","") %>
|
||||||
|
<%= raw form_field(@server,"name",nil,"server.domain","") %>
|
||||||
|
<%= raw single_action('send','compose',"up.png") %>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
16
app/views/user/unknown.html.erb
Executable file
16
app/views/user/unknown.html.erb
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
<% content_for :title do %>
|
||||||
|
<%= t(:unknown_title,:scope=>:user) %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<div class="box2">
|
||||||
|
<div class="logo"><a href="/"><img src="" alt="Mailr"/></a>
|
||||||
|
</div>
|
||||||
|
<h2><%= t(:unknown_title,:scope=>:user) %></h2>
|
||||||
|
<div class="content">
|
||||||
|
<div class="flash"><div class="message warning"><p><%= t(:unknown_flash,:scope=>:user) %></p></div></div>
|
||||||
|
<p><%= t(:unknown_login,:scope=>:user) %> -> <%= link_to t(:login,:scope=>:user),user_login_path %></p>
|
||||||
|
<p><%= t(:unknown_setup,:scope=>:user) %> -> <%= link_to t(:setup,:scope=>:user),:controller => "user",:action => "setup",:login => params[:login] %></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
BIN
arts/favicon.png
Executable file
BIN
arts/favicon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
arts/favicon.xcf
Executable file
BIN
arts/favicon.xcf
Executable file
Binary file not shown.
BIN
arts/logo.png
Executable file
BIN
arts/logo.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
BIN
arts/logo.xcf
Executable file
BIN
arts/logo.xcf
Executable file
Binary file not shown.
BIN
arts/logo2.xcf
Executable file
BIN
arts/logo2.xcf
Executable file
Binary file not shown.
BIN
arts/logo3.xcf
Executable file
BIN
arts/logo3.xcf
Executable file
Binary file not shown.
|
@ -17,6 +17,7 @@ module Mailr
|
||||||
|
|
||||||
# Custom directories with classes and modules you want to be autoloadable.
|
# Custom directories with classes and modules you want to be autoloadable.
|
||||||
# config.autoload_paths += %W(#{config.root}/extras)
|
# config.autoload_paths += %W(#{config.root}/extras)
|
||||||
|
config.autoload_paths += %W(#{config.root}/lib)
|
||||||
|
|
||||||
# Only load the plugins named here, in the order given (default is alphabetical).
|
# Only load the plugins named here, in the order given (default is alphabetical).
|
||||||
# :all can be used as a placeholder for all plugins not explicitly named.
|
# :all can be used as a placeholder for all plugins not explicitly named.
|
||||||
|
@ -28,6 +29,7 @@ module Mailr
|
||||||
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
||||||
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
||||||
# config.time_zone = 'Central Time (US & Canada)'
|
# config.time_zone = 'Central Time (US & Canada)'
|
||||||
|
config.time_zone = 'Warsaw'
|
||||||
|
|
||||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||||
|
@ -57,3 +59,14 @@ module Mailr
|
||||||
config.assets.version = '1.0'
|
config.assets.version = '1.0'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class ActiveSupport::BufferedLogger
|
||||||
|
def custom(desc,t)
|
||||||
|
info "\n**** #{desc} *****"
|
||||||
|
info t
|
||||||
|
info "**********************\n\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MailrException < Exception
|
||||||
|
end
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
# MySQL. Versions 4.1 and 5.0 are recommended.
|
|
||||||
#
|
|
||||||
# Install the MYSQL driver
|
|
||||||
# gem install mysql2
|
|
||||||
#
|
|
||||||
# Ensure the MySQL gem is defined in your Gemfile
|
|
||||||
# gem 'mysql2'
|
|
||||||
#
|
|
||||||
# And be sure to use new-style password hashing:
|
|
||||||
# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
|
|
||||||
development:
|
|
||||||
adapter: mysql2
|
|
||||||
encoding: utf8
|
|
||||||
reconnect: false
|
|
||||||
database: mailr_development
|
|
||||||
pool: 5
|
|
||||||
username: root
|
|
||||||
password:
|
|
||||||
host: localhost
|
|
||||||
|
|
||||||
# Warning: The database defined as "test" will be erased and
|
|
||||||
# re-generated from your development database when you run "rake".
|
|
||||||
# Do not set this db to the same as development or production.
|
|
||||||
test:
|
|
||||||
adapter: mysql2
|
|
||||||
encoding: utf8
|
|
||||||
reconnect: false
|
|
||||||
database: mailr_test
|
|
||||||
pool: 5
|
|
||||||
username: root
|
|
||||||
password:
|
|
||||||
host: localhost
|
|
||||||
|
|
||||||
production:
|
|
||||||
adapter: mysql2
|
|
||||||
encoding: utf8
|
|
||||||
reconnect: false
|
|
||||||
database: mailr_production
|
|
||||||
pool: 5
|
|
||||||
username: root
|
|
||||||
password:
|
|
||||||
host: localhost
|
|
|
@ -1,20 +1,42 @@
|
||||||
|
# MySQL. Versions 4.1 and 5.0 are recommended.
|
||||||
|
#
|
||||||
|
# Install the MYSQL driver
|
||||||
|
# gem install mysql2
|
||||||
|
#
|
||||||
|
# Ensure the MySQL gem is defined in your Gemfile
|
||||||
|
# gem 'mysql2'
|
||||||
|
#
|
||||||
|
# And be sure to use new-style password hashing:
|
||||||
|
# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
|
||||||
development:
|
development:
|
||||||
adapter: mysql
|
adapter: mysql2
|
||||||
database: mailr_dev
|
encoding: utf8
|
||||||
host: localhost
|
reconnect: false
|
||||||
|
database: mailr_development
|
||||||
|
pool: 5
|
||||||
username: root
|
username: root
|
||||||
password:
|
password:
|
||||||
|
socket: /var/run/mysqld/mysqld.sock
|
||||||
|
|
||||||
|
# Warning: The database defined as "test" will be erased and
|
||||||
|
# re-generated from your development database when you run "rake".
|
||||||
|
# Do not set this db to the same as development or production.
|
||||||
test:
|
test:
|
||||||
adapter: mysql
|
adapter: mysql2
|
||||||
database: mailr_tests
|
encoding: utf8
|
||||||
host: localhost
|
reconnect: false
|
||||||
|
database: mailr_test
|
||||||
|
pool: 5
|
||||||
username: root
|
username: root
|
||||||
password:
|
password:
|
||||||
|
socket: /var/run/mysqld/mysqld.sock
|
||||||
|
|
||||||
production:
|
production:
|
||||||
adapter: mysql
|
adapter: mysql2
|
||||||
database: mailr
|
encoding: utf8
|
||||||
host: localhost
|
reconnect: false
|
||||||
|
database: mailr_production
|
||||||
|
pool: 5
|
||||||
username: root
|
username: root
|
||||||
password:
|
password:
|
||||||
|
socket: /var/run/mysqld/mysqld.sock
|
||||||
|
|
66
config/locales/en.yml
Normal file → Executable file
66
config/locales/en.yml
Normal file → Executable file
|
@ -1,5 +1,63 @@
|
||||||
# Sample localization file for English. Add more files in this directory for other locales.
|
|
||||||
# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
|
|
||||||
|
|
||||||
en:
|
en:
|
||||||
hello: "Hello world"
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
prefs:
|
||||||
|
theme: Theme
|
||||||
|
locale: Locale
|
||||||
|
msgs_per_page: Messages per page
|
||||||
|
msg_send_type: Message send format
|
||||||
|
contact:
|
||||||
|
compose_to_selected: Compose to selected
|
||||||
|
delete_selected: Delete selected
|
||||||
|
modifying: Modifying contact
|
||||||
|
creating_new: Creating new contact
|
||||||
|
create_new: Create new contact
|
||||||
|
contacts: Contacts
|
||||||
|
contact: Contact
|
||||||
|
no_selected: No contact selected
|
||||||
|
total_entries: Total contacts entries
|
||||||
|
no_entries: No contacts
|
||||||
|
was_created: Contact was created
|
||||||
|
are_you_sure_to_delete_contact: Are You sure to delete contact?
|
||||||
|
|
||||||
|
prefs:
|
||||||
|
prefs: Preferences
|
||||||
|
|
||||||
|
folder:
|
||||||
|
folders: Folders
|
||||||
|
no_shown: No folders shown
|
||||||
|
parent: Parent folder
|
||||||
|
to_create: Folder to create
|
||||||
|
to_delete: Folder to delete
|
||||||
|
shown: Shown folders
|
||||||
|
emptybin: Empty
|
||||||
|
current: Current folder
|
||||||
|
no_selected: No folder selected
|
||||||
|
to_create_empty: No folder name
|
||||||
|
max_depth: Maximum folder depth reached
|
||||||
|
can_not_create: Can not create folder
|
||||||
|
was_created: Folder was created
|
||||||
|
to_delete_empty: No folder to delete
|
||||||
|
can_not_delete: Can not delete folder
|
||||||
|
was_deleted: Folder was deleted
|
||||||
|
|
||||||
|
message:
|
||||||
|
messages: Messages
|
||||||
|
|
||||||
|
compose:
|
||||||
|
compose: Compose
|
||||||
|
|
||||||
|
user:
|
||||||
|
login_failure: Login failure. Bad email or password
|
||||||
|
logged_out: User was logged out
|
||||||
|
setup_done: Setup done. Please login in
|
||||||
|
|
||||||
|
must_be_unique: must be unique
|
||||||
|
some_add_info: some additional information
|
||||||
|
example: example
|
||||||
|
refresh: Refresh
|
||||||
|
create: Create
|
||||||
|
delete: Delete
|
||||||
|
show_hide: Show/Hide
|
||||||
|
mailr: Mailr
|
||||||
|
save: Save
|
||||||
|
|
91
config/locales/es-ES.yml
Executable file
91
config/locales/es-ES.yml
Executable file
|
@ -0,0 +1,91 @@
|
||||||
|
es-ES:
|
||||||
|
mailr: Mailr
|
||||||
|
email: Email
|
||||||
|
password: Contraseña
|
||||||
|
log_in: Iniciar sesión
|
||||||
|
wrong_email_or_password: Email o contraseña incorrecta
|
||||||
|
mailbox: Buzon de Correo
|
||||||
|
folders: Carpetas
|
||||||
|
folder: Carpeta
|
||||||
|
empty: Vaciar
|
||||||
|
logout: Cerrar sesión
|
||||||
|
compose: Redactar
|
||||||
|
preferences: Opciones
|
||||||
|
filters: Filtros
|
||||||
|
contacts: Contactos
|
||||||
|
search: Buscar
|
||||||
|
search_txt: Buscar en el campo
|
||||||
|
refresh: Refrescar
|
||||||
|
operations: Operaciones
|
||||||
|
operations_txt: Operaciones en mensajes marcados
|
||||||
|
delete: borrar
|
||||||
|
copy: copiar
|
||||||
|
move: mover
|
||||||
|
junk: Basura
|
||||||
|
sent: Enviados
|
||||||
|
inbox: Bandeja de Entrada
|
||||||
|
trash: Basura
|
||||||
|
drafts: Borradores
|
||||||
|
mark_read: marcar como leido
|
||||||
|
mark_unread: marcar comono leido
|
||||||
|
destination_txt: Destino para operaciones de copiado y movido
|
||||||
|
for: para
|
||||||
|
to: Para
|
||||||
|
subject: Asunto
|
||||||
|
date: Fecha
|
||||||
|
size: Tamaño
|
||||||
|
from: De
|
||||||
|
show_all: Mostrar todos
|
||||||
|
pages: Páginas
|
||||||
|
first: Primero
|
||||||
|
prev: Previo
|
||||||
|
next: Siguiente
|
||||||
|
last: Último
|
||||||
|
back_to_list: Volver a la lista
|
||||||
|
back_to_message: Volver al mensaje
|
||||||
|
reply: Responder
|
||||||
|
forward: Reenviar
|
||||||
|
view_source: Ver fuente
|
||||||
|
add_filter: Agregar filtro
|
||||||
|
cc: CC
|
||||||
|
bcc: BCC
|
||||||
|
send: Enviar
|
||||||
|
choose_address: Elegir dirección desde contactos
|
||||||
|
choose: Elegir
|
||||||
|
compose_txt: Componer nuevo correo
|
||||||
|
groups: Grupos
|
||||||
|
attachment: Adjunto
|
||||||
|
add: Agregar
|
||||||
|
first_name: Nombre
|
||||||
|
last_name: Apellido
|
||||||
|
send_type: Enviar mensaje tipo
|
||||||
|
messages_per_page: Mensajes por página
|
||||||
|
check_external_mail: Comprobar correos externos?
|
||||||
|
check_external_mail_txt: Note that by selecting this option webmail system will try to log you using your original email on a local server.
|
||||||
|
save: Guardar
|
||||||
|
save_and_add_another: Guardar y agregar otro
|
||||||
|
cancel: Cancelar
|
||||||
|
add_one_contact: Agregar un contacto
|
||||||
|
add_multiple: Agregar multiples
|
||||||
|
add_multiple_contacts: Agregar multiples contactos
|
||||||
|
name: nombre
|
||||||
|
add_folder: Agregar carpeta
|
||||||
|
total_messages: Mensajes totales
|
||||||
|
unseen: No leidos
|
||||||
|
edit_create_contact: Editar o crear contacto
|
||||||
|
back_to_contacts: Volver a contactos
|
||||||
|
email_exists: Una cuenta con ese correo electrónico ya existe.
|
||||||
|
delete_contact_question: "Desea borrar este contacto? {{name}} - {{email}}"
|
||||||
|
validate_fname_error: Por favor, ingrese un nombre (2 a 20 caracteres)
|
||||||
|
validate_lname_error: Por favor, ingrese un apellido (2 a 20 caracteres)
|
||||||
|
validate_email_error: Por favor, ingrese una dirección email válida.
|
||||||
|
contact_cannot_be_changed: El email del contacto no puede ser cambiado
|
||||||
|
csv_file: Archivo separado por comas(CSV)
|
||||||
|
tab_file: Archivo separado por tabulaciones
|
||||||
|
select_file: Selecionar archivo
|
||||||
|
import: Importar
|
||||||
|
back_to_folders: Volver a carpetas
|
||||||
|
add_edit_folder: agregar/editar
|
||||||
|
user_logged_out: Sesión cerrada correctamente
|
||||||
|
please_login: Por favor, inicie sesión
|
||||||
|
want_to_empty_trash_message: ¿Realmente quieres vaciar la papelera?
|
227
config/locales/pl.yml
Executable file
227
config/locales/pl.yml
Executable file
|
@ -0,0 +1,227 @@
|
||||||
|
pl:
|
||||||
|
date:
|
||||||
|
day_names: [Niedziela, Poniedziałek, Wtorek, Środa, Czwartek, Piątek, Sobota]
|
||||||
|
abbr_day_names: [Ni, Po, Wt, Śr, Cz, Pi, So]
|
||||||
|
month_names: [~, Styczeń, Luty, Marzec, Kwiecień, Maj, Czerwiec, Lipiec, Sierpień, Wrzesień, Październik, Listopad, Grudzień]
|
||||||
|
abbr_month_names: [~, Sty, Lut, Mar, Kwi, Maj, Czer, Lip, Sier, Wrze, Paź, Lis, Grudz]
|
||||||
|
order: [ :year, :month, :day ]
|
||||||
|
activerecord:
|
||||||
|
errors:
|
||||||
|
messages:
|
||||||
|
blank: "nie może być pust(a/e/y) "
|
||||||
|
too_short: "za krótki(e) (min. %{count} znak(i/ów)) "
|
||||||
|
too_long: "za długi(e) (max. %{count} znak(i/ów)) "
|
||||||
|
invalid: "ma niepoprawny format "
|
||||||
|
not_unique: "musi być unikalny "
|
||||||
|
taken: "musi być unikalny"
|
||||||
|
record_invalid: Nieprawidłowy format danych
|
||||||
|
models:
|
||||||
|
contact: Kontakt
|
||||||
|
server: Serwer
|
||||||
|
link: Sznurek
|
||||||
|
attributes:
|
||||||
|
link:
|
||||||
|
name: Nazwa
|
||||||
|
url: Adres
|
||||||
|
info: Informacje
|
||||||
|
contact:
|
||||||
|
nick: Pseudonim
|
||||||
|
first_name: Imię
|
||||||
|
last_name: Nazwisko
|
||||||
|
email: E-mail
|
||||||
|
info: Informacje dodatkowe
|
||||||
|
prefs:
|
||||||
|
theme: Temat
|
||||||
|
locale: Ustawienia językowe
|
||||||
|
msgs_per_page: Ilość wiadomości wyświetlanych na stronie
|
||||||
|
msg_send_type: Format wysyłanej wiadomości
|
||||||
|
msg_image_view_as: Prezentuj obraz jako
|
||||||
|
msg_image_thumbnail_size: Rozmiar miniaturki obrazu
|
||||||
|
message:
|
||||||
|
from_addr: Od
|
||||||
|
to_addr: Do
|
||||||
|
subject: Temat
|
||||||
|
size: Rozmiar
|
||||||
|
date: Data
|
||||||
|
body: Treść
|
||||||
|
cc_addr: Dw
|
||||||
|
bcc_addr: UDw
|
||||||
|
user:
|
||||||
|
email: E-mail
|
||||||
|
password: Hasło
|
||||||
|
first_name: Imię
|
||||||
|
last_name: Nazwisko
|
||||||
|
domain: Domena
|
||||||
|
server:
|
||||||
|
name: Nazwa serwera
|
||||||
|
port: Port
|
||||||
|
use_ssl: SSL?
|
||||||
|
use_tls: TLS?
|
||||||
|
for_imap: IMAP?
|
||||||
|
for_smtp: SMTP?
|
||||||
|
auth: Metoda autoryzacji
|
||||||
|
|
||||||
|
contact:
|
||||||
|
compose_to_selected: Napisz do wybranych
|
||||||
|
delete_selected: Usuń wybrane
|
||||||
|
modifying: Modyfikacja kontaktu
|
||||||
|
creating_new: Nowy kontakt
|
||||||
|
create_new: Utwórz nowy kontakt
|
||||||
|
contacts: Kontakty
|
||||||
|
contact: Kontakt
|
||||||
|
no_selected: Nie wybrano żadnego kontaktu
|
||||||
|
total_entries: Liczba kontaktów
|
||||||
|
no_entries: Brak kontaktów
|
||||||
|
was_created: Kontakt został utworzony
|
||||||
|
are_you_sure_to_delete_contact: Czy na pewno chcesz usunąć kontakt?
|
||||||
|
export: Export
|
||||||
|
import: Import
|
||||||
|
were_imported: Kontakty zostały zaimportowane
|
||||||
|
format_error: Nieprawidłowy format kontaktu
|
||||||
|
|
||||||
|
link:
|
||||||
|
link: Sznurek
|
||||||
|
links: Sznurki
|
||||||
|
create_new: Utwórz nowy sznurek
|
||||||
|
no_entries: Brak sznurków
|
||||||
|
total_entries: Liczba sznurków
|
||||||
|
delete_selected: Usuń wybrane
|
||||||
|
|
||||||
|
prefs:
|
||||||
|
prefs: Ustawienia
|
||||||
|
look: Wygląd
|
||||||
|
identity: Tożsamość
|
||||||
|
servers: Serwery
|
||||||
|
were_saved: Ustawienia zostały zapisane
|
||||||
|
thumbnail: Miniaturka
|
||||||
|
attachment: Załącznik
|
||||||
|
|
||||||
|
folder:
|
||||||
|
folder: Folder
|
||||||
|
folders: Foldery
|
||||||
|
no_shown: Nie prezentowany jest żaden folder. Skonfiguruj widok folderów w zakładce
|
||||||
|
parent: Folder nadrzędny
|
||||||
|
to_create: Folder do utworzenia
|
||||||
|
to_delete: Folder do usunięcia
|
||||||
|
shown: Wyświetlane foldery
|
||||||
|
emptybin: Opróżnij
|
||||||
|
current: Folder bieżący
|
||||||
|
no_selected: Nie wybrano żadnego folderu
|
||||||
|
to_create_empty: Nie podano nazwy folderu
|
||||||
|
max_depth: Osiągnięto maksymalne zagnieżdzenie fodlderów
|
||||||
|
can_not_create: Nie można utworzyć folderu
|
||||||
|
was_created: Folder został utworzony
|
||||||
|
to_delete_empty: Nie wybrano folderu do usunięcia
|
||||||
|
can_not_delete: Nie można usunąć folderu
|
||||||
|
was_deleted: Folder został usunięty
|
||||||
|
to_folder: do folderu
|
||||||
|
system: Folder systemowy
|
||||||
|
not_all_configured: Nie wszystkie systemowe foldery zostały skonfigurowane
|
||||||
|
inbox_name: Odebrane
|
||||||
|
sent_name: Wysłane
|
||||||
|
trash_name: Kosz
|
||||||
|
drafts_name: Roboczy
|
||||||
|
not_configured_drafts: Folder Roboczy nie został przypisany
|
||||||
|
not_configured_sent: Folder Wysłany nie został przypisany
|
||||||
|
not_configured_trash: Folder Kosz nie został przypisany
|
||||||
|
not_configured_inbox: Folder Odebrane nie został przypisany
|
||||||
|
show_hide: Pokaż/Ukryj
|
||||||
|
refresh: Odśwież
|
||||||
|
|
||||||
|
message:
|
||||||
|
messages: Wiadomości
|
||||||
|
no_selected: Nie wybrano żadnej wiadomości
|
||||||
|
total: Liczba wszystkich wiadomości
|
||||||
|
checked: zaznaczone wiadomości
|
||||||
|
set_read: Ustaw jako przeczytane
|
||||||
|
set_unread: Ustaw jako nieprzeczytane
|
||||||
|
no_in: Nie ma żadnych wiadomości w bieżącym folderze
|
||||||
|
no_subject: Brak tematu
|
||||||
|
no_content: Wiadomość nie zawiera treści
|
||||||
|
attachments: Załączniki
|
||||||
|
content: Treść wiadomości
|
||||||
|
header_source: Nagłówek wiadomości
|
||||||
|
show_header: Pokaż nagłówek
|
||||||
|
edit: Edycja
|
||||||
|
images: Obrazy
|
||||||
|
delete: Usuń zaznaczone
|
||||||
|
move: Przenieś
|
||||||
|
copy: Skopiuj
|
||||||
|
trash: Usuń zaznaczone
|
||||||
|
no_date: Brak daty
|
||||||
|
|
||||||
|
compose:
|
||||||
|
compose: Nowa wiadomość
|
||||||
|
new_message: Nowa wiadomość
|
||||||
|
not_contain_at: ",jeżeli nie zawiera znaku @, adres będzie szukany w kontaktach"
|
||||||
|
subject_of_the_message: Temat wiadomości
|
||||||
|
write_your_message_here: Tu wpisz swoją wiadomość
|
||||||
|
was_sent: Wiadomość została wysłana
|
||||||
|
was_saved: Wiadomość została zapisana w katalogu roboczym
|
||||||
|
not_configured_smtp: Brak konfiguracji SMTP
|
||||||
|
select_file: Wybierz plik
|
||||||
|
delete_marked: Usuń zaznaczone
|
||||||
|
upload: Wyślij plik
|
||||||
|
sendout: Wyślij
|
||||||
|
save: Zapisz w katalogu roboczym
|
||||||
|
|
||||||
|
show:
|
||||||
|
reply: Odpowiedz
|
||||||
|
show_header: Pokaż nagłówek
|
||||||
|
delete: Usuń
|
||||||
|
reply_string: "Odp: "
|
||||||
|
trash: Usuń
|
||||||
|
|
||||||
|
user:
|
||||||
|
login_failure: Nieudane logowanie. Podano błędny e-mail lub hasło.
|
||||||
|
logged_out: Użytkownik wylogowany
|
||||||
|
setup_done: Konfiguracja zakończona. Proszę się zalogować.
|
||||||
|
please_login: Logowanie
|
||||||
|
unknown_title: Nieznany użytkownik
|
||||||
|
unknown_flash: Twój identyfikator użytkownika nie został odnaleziony w bazie
|
||||||
|
unknown_login: Idź do strony logowania i zaloguj sie jeszcze raz
|
||||||
|
unknown_setup: Idź do strony konfiguracyjnej i skonfiguruj swój dostęp
|
||||||
|
setup: Konfiguracja
|
||||||
|
login: Logowanie
|
||||||
|
only_can_logins: Podany identyfikator użytkownika nie uprawnia do korzystania z aplikacji
|
||||||
|
logout: Wyloguj
|
||||||
|
has_no_domain: Użytkownik nie ma ustawionej domeny
|
||||||
|
|
||||||
|
internal:
|
||||||
|
imap_error: Błąd protokołu IMAP
|
||||||
|
unspecified_error: Nieoczekiwany błąd
|
||||||
|
not_found: Nie znaleziono żądanej strony
|
||||||
|
internal_server_error: Błąd aplikacji
|
||||||
|
unprocessable_entity: Błąd procesowania
|
||||||
|
about: Informacje o programie
|
||||||
|
current_version: Aktualna wersja
|
||||||
|
general_error: Błąd aplikacji
|
||||||
|
|
||||||
|
common:
|
||||||
|
false_answer: Nie
|
||||||
|
true_answer: Tak
|
||||||
|
file_format_error: Błędny format pliku
|
||||||
|
no_tmp_dir: Brak katalogu tymczasowego
|
||||||
|
must_be_unique: musi być unikalny
|
||||||
|
some_add_info: jakieś dodatkowe informacje
|
||||||
|
example: przykład
|
||||||
|
create: Utwórz
|
||||||
|
delete: Usuń
|
||||||
|
mailr: MailR
|
||||||
|
save: Zapisz
|
||||||
|
copy: Skopiuj
|
||||||
|
move: Przenieś
|
||||||
|
to: do
|
||||||
|
previous_page: Poprzednia
|
||||||
|
next_page: Następna
|
||||||
|
bytes: B
|
||||||
|
kbytes: kB
|
||||||
|
mbytes: MB
|
||||||
|
site_link: https://github.com/lmanolov/mailr
|
||||||
|
no_data: Brak danych
|
||||||
|
download: Pobierz
|
||||||
|
view: Pokaż
|
||||||
|
version: Wersja
|
||||||
|
set: Ustaw
|
||||||
|
no_file_chosen: Nie wybrano żadnego pliku
|
||||||
|
calendar: Kalendarz
|
131
config/routes.rb
Normal file → Executable file
131
config/routes.rb
Normal file → Executable file
|
@ -1,58 +1,79 @@
|
||||||
Mailr::Application.routes.draw do
|
Mailr::Application.routes.draw do
|
||||||
# The priority is based upon order of creation:
|
|
||||||
# first created -> highest priority.
|
|
||||||
|
|
||||||
# Sample of regular route:
|
namespace :prefs do
|
||||||
# match 'products/:id' => 'catalog#view'
|
post "update_look"
|
||||||
# Keep in mind you can assign values other than :controller and :action
|
post "update_identity"
|
||||||
|
post "update_servers"
|
||||||
# Sample of named route:
|
end
|
||||||
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
|
match "prefs/look" => "prefs#look", :as => :prefs_look
|
||||||
# This route can be invoked with purchase_url(:id => product.id)
|
match "prefs/identity" => "prefs#identity", :as => :prefs_identity
|
||||||
|
match "prefs/servers" => "prefs#servers", :as => :prefs_servers
|
||||||
# Sample resource route (maps HTTP verbs to controller actions automatically):
|
|
||||||
# resources :products
|
namespace :contacts do
|
||||||
|
post "ops"
|
||||||
# Sample resource route with options:
|
get "export"
|
||||||
# resources :products do
|
end
|
||||||
# member do
|
match "/external" => "contacts#external", :as => :contacts_external
|
||||||
# get 'short'
|
|
||||||
# post 'toggle'
|
resources :contacts
|
||||||
# end
|
|
||||||
#
|
namespace :links do
|
||||||
# collection do
|
post "ops"
|
||||||
# get 'sold'
|
get "export"
|
||||||
# end
|
end
|
||||||
# end
|
#match "/external" => "contacts#external", :as => :contacts_external
|
||||||
|
|
||||||
# Sample resource route with sub-resources:
|
|
||||||
# resources :products do
|
resources :links
|
||||||
# resources :comments, :sales
|
|
||||||
# resource :seller
|
namespace :folders do
|
||||||
# end
|
post "create"
|
||||||
|
post "delete"
|
||||||
# Sample resource route with more complex sub-resources
|
post "system"
|
||||||
# resources :products do
|
post "show_hide"
|
||||||
# resources :comments
|
post "refresh"
|
||||||
# resources :sales do
|
get "refresh_status"
|
||||||
# get 'recent', :on => :collection
|
get "emptybin"
|
||||||
# end
|
end
|
||||||
# end
|
match "/folders/index" => 'folders#index', :as => :folders
|
||||||
|
match "/folders/select/:id" => 'folders#select', :as => :folders_select
|
||||||
# Sample resource route within a namespace:
|
|
||||||
# namespace :admin do
|
namespace :internal do
|
||||||
# # Directs /admin/products/* to Admin::ProductsController
|
get "error"
|
||||||
# # (app/controllers/admin/products_controller.rb)
|
get "imaperror"
|
||||||
# resources :products
|
get "loginfailure"
|
||||||
# end
|
get "onlycanlogins"
|
||||||
|
end
|
||||||
# You can have the root of your site routed with "root"
|
match "/internal/about" => 'internal#about' ,:as => :about
|
||||||
# just remember to delete public/index.html.
|
|
||||||
# root :to => 'welcome#index'
|
match "/messages_ops/single" => 'messages_ops#single'
|
||||||
|
match "/messages_ops/multi" => 'messages_ops#multi'
|
||||||
# See how all your routes lay out with "rake routes"
|
match "/messages_ops/sendout_or_save" => 'messages_ops#sendout_or_save' ,:as =>:sendout_or_save
|
||||||
|
match "/messages_ops/upload" => 'messages_ops#upload',:as => :upload
|
||||||
# This is a legacy wild controller route that's not recommended for RESTful applications.
|
match "/messages_ops/edit/:id" => 'messages_ops#edit', :as => :edit
|
||||||
# Note: This route will make all actions in every controller accessible via GET requests.
|
match "/messages_ops/composed" => 'messages_ops#composed', :as => :composed
|
||||||
# match ':controller(/:action(/:id))(.:format)'
|
|
||||||
|
root :to => "messages#index"
|
||||||
|
|
||||||
|
match "/messages/index" => 'messages#index', :as => :messages
|
||||||
|
match "/messages/compose" => 'messages#compose', :as => :compose
|
||||||
|
match "/messages/compose/:cid" => 'messages#compose', :as => :compose_contact
|
||||||
|
match "/messages/show/:id" => 'messages#show'
|
||||||
|
match "/messages/html_body/:id" => 'messages#html_body' , :as => :html_body
|
||||||
|
match "/messages/attachment/:id/:idx" => 'messages#attachment', :as => :attachment_download
|
||||||
|
|
||||||
|
namespace :user do
|
||||||
|
get "logout"
|
||||||
|
post "authenticate"
|
||||||
|
post "create"
|
||||||
|
get "login"
|
||||||
|
get "setup"
|
||||||
|
get "unknown"
|
||||||
|
end
|
||||||
|
match "/user/setup/:login" => 'user#setup'
|
||||||
|
|
||||||
|
#themes_for_rails
|
||||||
|
|
||||||
|
#match '*a', :to => 'internal#not_found'
|
||||||
|
#match ':controller(/:action(/:id(.:format)))'
|
||||||
end
|
end
|
||||||
|
|
53
config/settings.yml.example
Normal file
53
config/settings.yml.example
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
version: 0.9
|
||||||
|
|
||||||
|
theme: olive
|
||||||
|
locale: pl
|
||||||
|
|
||||||
|
themes: [olive]
|
||||||
|
locales: [en, pl]
|
||||||
|
msgs_per_page_table: [15, 20, 25, 30, 35, 40, 45, 50]
|
||||||
|
msg_send_type: [html, text]
|
||||||
|
msg_image_view_as: [attachment, thumbnail]
|
||||||
|
msg_image_thumbnail_size: [128x128, 128x96, 192x192, 192x144, 256x256, 256x192]
|
||||||
|
|
||||||
|
contacts_table_fields: [nick, first_name, last_name, email, info]
|
||||||
|
contacts_per_page: 25
|
||||||
|
|
||||||
|
links_table_fields: [name, url, info]
|
||||||
|
links_per_page: 30
|
||||||
|
|
||||||
|
servers_table_fields: [name, port, use_ssl, use_tls, for_imap, for_smtp, auth]
|
||||||
|
|
||||||
|
msgs_per_page: 20
|
||||||
|
msgs_refresh_time: 300
|
||||||
|
msgs_send_type: html
|
||||||
|
msgs_update_time: 600
|
||||||
|
msgs_inbox_view_fields: [from_addr, subject, date, size]
|
||||||
|
msgs_sent_view_fields: [to_addr, subject, date, size]
|
||||||
|
|
||||||
|
msg_subject_length: 50
|
||||||
|
msg_address_length: 35
|
||||||
|
msg_search_fields: [subject, from, to]
|
||||||
|
msg_upload_dir: "tmp/uploads"
|
||||||
|
|
||||||
|
contact_tmp_filename: contact_import
|
||||||
|
|
||||||
|
# if encoding can not be get from data
|
||||||
|
msg_unknown_charset: ISO-8859-2
|
||||||
|
|
||||||
|
imap_debug: true
|
||||||
|
imap_use_ssl: 'false'
|
||||||
|
imap_port: 143
|
||||||
|
imap_ssl_port: 993
|
||||||
|
imap_bye_timeout_retry_seconds: 2
|
||||||
|
imap_fetch_slice: 20
|
||||||
|
|
||||||
|
smtp_port: 25
|
||||||
|
|
||||||
|
session_encryption: true
|
||||||
|
session_password: asDD3s2@sAdc983#
|
||||||
|
|
||||||
|
mailbox_max_parent_folder_depth: 3
|
||||||
|
|
||||||
|
# array of logins which only can login to application, comment it to allow everyone to login
|
||||||
|
only_can_logins: ['somelogin1']
|
111
db/migrate/20120303202800_create_all_tables.rb
Normal file
111
db/migrate/20120303202800_create_all_tables.rb
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
class CreateAllTables < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
create_table "contacts", :force => true do |t|
|
||||||
|
t.string "nick"
|
||||||
|
t.string "email"
|
||||||
|
t.string "first_name"
|
||||||
|
t.string "last_name"
|
||||||
|
t.string "info"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "events", :force => true do |t|
|
||||||
|
t.integer "user_id"
|
||||||
|
t.integer "priority"
|
||||||
|
t.text "description"
|
||||||
|
t.string "category"
|
||||||
|
t.datetime "start"
|
||||||
|
t.datetime "stop"
|
||||||
|
t.boolean "allday"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "folders", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.string "delim"
|
||||||
|
t.boolean "haschildren"
|
||||||
|
t.integer "total"
|
||||||
|
t.integer "unseen"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.string "parent"
|
||||||
|
t.boolean "shown"
|
||||||
|
t.string "alter_name"
|
||||||
|
t.integer "sys"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "messages", :id => false, :force => true do |t|
|
||||||
|
t.integer "folder_id"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.string "msg_id"
|
||||||
|
t.string "from_addr"
|
||||||
|
t.string "to_addr"
|
||||||
|
t.string "subject"
|
||||||
|
t.string "content_type"
|
||||||
|
t.integer "uid"
|
||||||
|
t.integer "size"
|
||||||
|
t.boolean "unseen"
|
||||||
|
t.datetime "date"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "prefs", :force => true do |t|
|
||||||
|
t.string "theme"
|
||||||
|
t.string "locale"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.string "msgs_per_page"
|
||||||
|
t.string "msg_send_type"
|
||||||
|
t.string "msg_image_view_as"
|
||||||
|
t.string "msg_image_thumbnail_size"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "servers", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.string "port"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.boolean "use_ssl"
|
||||||
|
t.boolean "use_tls"
|
||||||
|
t.boolean "for_imap"
|
||||||
|
t.boolean "for_smtp"
|
||||||
|
t.string "auth"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "users", :force => true do |t|
|
||||||
|
t.string "login"
|
||||||
|
t.string "first_name"
|
||||||
|
t.string "last_name"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.string "domain"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :links, :force => true do |t|
|
||||||
|
t.integer :user_id
|
||||||
|
t.integer :lgroup_id
|
||||||
|
t.string :name
|
||||||
|
t.string :url
|
||||||
|
t.string :info
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
drop_table "contacts"
|
||||||
|
drop_table "events"
|
||||||
|
drop_table "folders"
|
||||||
|
drop_table "prefs"
|
||||||
|
drop_table "servers"
|
||||||
|
drop_table "users"
|
||||||
|
drop_table "links"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
111
db/schema.rb
Normal file
111
db/schema.rb
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
# This file is auto-generated from the current state of the database. Instead
|
||||||
|
# of editing this file, please use the migrations feature of Active Record to
|
||||||
|
# incrementally modify your database, and then regenerate this schema definition.
|
||||||
|
#
|
||||||
|
# Note that this schema.rb definition is the authoritative source for your
|
||||||
|
# database schema. If you need to create the application database on another
|
||||||
|
# system, you should be using db:schema:load, not running all the migrations
|
||||||
|
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
||||||
|
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
||||||
|
#
|
||||||
|
# It's strongly recommended to check this file into your version control system.
|
||||||
|
|
||||||
|
ActiveRecord::Schema.define(:version => 20120303202800) do
|
||||||
|
|
||||||
|
create_table "contacts", :force => true do |t|
|
||||||
|
t.string "nick"
|
||||||
|
t.string "email"
|
||||||
|
t.string "first_name"
|
||||||
|
t.string "last_name"
|
||||||
|
t.string "info"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "events", :force => true do |t|
|
||||||
|
t.integer "user_id"
|
||||||
|
t.integer "priority"
|
||||||
|
t.text "description"
|
||||||
|
t.string "category"
|
||||||
|
t.datetime "start"
|
||||||
|
t.datetime "stop"
|
||||||
|
t.boolean "allday"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "folders", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.string "delim"
|
||||||
|
t.boolean "haschildren"
|
||||||
|
t.integer "total"
|
||||||
|
t.integer "unseen"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.string "parent"
|
||||||
|
t.boolean "shown"
|
||||||
|
t.string "alter_name"
|
||||||
|
t.integer "sys"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "links", :force => true do |t|
|
||||||
|
t.integer "user_id"
|
||||||
|
t.integer "lgroup_id"
|
||||||
|
t.string "name"
|
||||||
|
t.string "url"
|
||||||
|
t.string "info"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "messages", :id => false, :force => true do |t|
|
||||||
|
t.integer "folder_id"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.string "msg_id"
|
||||||
|
t.string "from_addr"
|
||||||
|
t.string "to_addr"
|
||||||
|
t.string "subject"
|
||||||
|
t.string "content_type"
|
||||||
|
t.integer "uid"
|
||||||
|
t.integer "size"
|
||||||
|
t.boolean "unseen"
|
||||||
|
t.datetime "date"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "prefs", :force => true do |t|
|
||||||
|
t.string "theme"
|
||||||
|
t.string "locale"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.string "msgs_per_page"
|
||||||
|
t.string "msg_send_type"
|
||||||
|
t.string "msg_image_view_as"
|
||||||
|
t.string "msg_image_thumbnail_size"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "servers", :force => true do |t|
|
||||||
|
t.string "name"
|
||||||
|
t.string "port"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.boolean "use_ssl"
|
||||||
|
t.boolean "use_tls"
|
||||||
|
t.boolean "for_imap"
|
||||||
|
t.boolean "for_smtp"
|
||||||
|
t.string "auth"
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "users", :force => true do |t|
|
||||||
|
t.string "login"
|
||||||
|
t.string "first_name"
|
||||||
|
t.string "last_name"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.datetime "updated_at"
|
||||||
|
t.string "domain"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
23
lib/imap_folder.rb
Executable file
23
lib/imap_folder.rb
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
require 'net/imap'
|
||||||
|
|
||||||
|
module ImapFolderModule
|
||||||
|
|
||||||
|
class IMAPFolder
|
||||||
|
|
||||||
|
attr_reader :utf7_name
|
||||||
|
attr_reader :delim
|
||||||
|
attr_reader :attribs
|
||||||
|
attr_reader :name
|
||||||
|
attr_accessor :messages
|
||||||
|
attr_accessor :unseen
|
||||||
|
|
||||||
|
def initialize(utf7_name,delim,attribs)
|
||||||
|
@utf7_name = utf7_name
|
||||||
|
@name = Net::IMAP.decode_utf7 utf7_name
|
||||||
|
@delim = delim
|
||||||
|
@attribs = attribs
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
207
lib/imap_mailbox.rb
Executable file
207
lib/imap_mailbox.rb
Executable file
|
@ -0,0 +1,207 @@
|
||||||
|
require 'net/imap'
|
||||||
|
require 'imap_folder'
|
||||||
|
|
||||||
|
module ImapMailboxModule
|
||||||
|
|
||||||
|
class IMAPError < RuntimeError
|
||||||
|
end
|
||||||
|
|
||||||
|
class IMAPMailbox
|
||||||
|
|
||||||
|
attr_reader :connected
|
||||||
|
attr_accessor :sfolder
|
||||||
|
attr_accessor :logger
|
||||||
|
|
||||||
|
def initialize(logger,debug)
|
||||||
|
@sfolder = ''
|
||||||
|
@folders = {}
|
||||||
|
@connected = false
|
||||||
|
@logger = logger
|
||||||
|
Net::IMAP.debug = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def connect(server,username,password)
|
||||||
|
|
||||||
|
server_name = server.name
|
||||||
|
server_port = server.port
|
||||||
|
server_use_ssl = server.use_ssl
|
||||||
|
|
||||||
|
unless @connected
|
||||||
|
begin
|
||||||
|
@imap = Net::IMAP.new(server_name, server_port, server_use_ssl)
|
||||||
|
rescue Net::IMAP::ByeResponseError => bye
|
||||||
|
begin
|
||||||
|
System.sleep($defaults["imap_bye_timeout_retry_seconds"])
|
||||||
|
@imap = Net::IMAP.new(server_name, server_port, server_use_ssl)
|
||||||
|
rescue Exception => ex
|
||||||
|
raise IMAPError, ex.inspect
|
||||||
|
end
|
||||||
|
rescue Exception => ex
|
||||||
|
raise IMAPError, ex.inspect
|
||||||
|
end
|
||||||
|
@username = username
|
||||||
|
begin
|
||||||
|
@imap.login(username, password)
|
||||||
|
@connected = true
|
||||||
|
rescue Exception => ex
|
||||||
|
raise IMAPError, ex.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def disconnect
|
||||||
|
if @connected
|
||||||
|
@imap.logout
|
||||||
|
@imap.disconnect
|
||||||
|
@imap = nil
|
||||||
|
@connected = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def folders
|
||||||
|
@folders = {}
|
||||||
|
folders = @imap.list('', '*')
|
||||||
|
if folders
|
||||||
|
folders.each do |f|
|
||||||
|
folder = ImapFolderModule::IMAPFolder.new(f.name,f.delim,f.attr)
|
||||||
|
status = @imap.status(folder.name, ["MESSAGES", "UNSEEN"])
|
||||||
|
folder.messages = status["MESSAGES"]
|
||||||
|
folder.unseen = status["UNSEEN"]
|
||||||
|
@folders[folder.name] = folder
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@folders
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_folder(name)
|
||||||
|
begin
|
||||||
|
@imap.create(Net::IMAP.encode_utf7(name))
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_uids
|
||||||
|
begin
|
||||||
|
uids = []
|
||||||
|
imap_uids = @imap.fetch(1..-1, "UID")
|
||||||
|
imap_uids.each do |u|
|
||||||
|
uids << u.attr['UID']
|
||||||
|
end
|
||||||
|
return uids
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_folder(name)
|
||||||
|
begin
|
||||||
|
@imap.delete(Net::IMAP.decode_utf7(name))
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch(range,attribs)
|
||||||
|
begin
|
||||||
|
@imap.fetch(range,attribs)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def uid_fetch(range,attribs)
|
||||||
|
begin
|
||||||
|
@imap.uid_fetch(range,attribs)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_folder(folder_name)
|
||||||
|
begin
|
||||||
|
if folder_name != @sfolder
|
||||||
|
@imap.select(folder_name)
|
||||||
|
@sfolder = folder_name
|
||||||
|
end
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def status
|
||||||
|
begin
|
||||||
|
@imap.status(@sfolder, ["MESSAGES", "RECENT", "UNSEEN"])
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_body(uid)
|
||||||
|
begin
|
||||||
|
uid_fetch(uid,"BODY[]").first.attr["BODY[]"]
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_message(uid)
|
||||||
|
begin
|
||||||
|
@imap.uid_store(uid.to_i, "+FLAGS", :Deleted)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def expunge
|
||||||
|
begin
|
||||||
|
@imap.expunge
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_read(uid)
|
||||||
|
begin
|
||||||
|
@imap.uid_store(uid.to_i, "+FLAGS", :Seen)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_unread(uid)
|
||||||
|
begin
|
||||||
|
@imap.uid_store(uid.to_i, "-FLAGS", :Seen)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy_message(uid,dest_folder)
|
||||||
|
begin
|
||||||
|
@imap.uid_copy(uid.to_i, dest_folder)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def move_message(uid,dest_folder)
|
||||||
|
begin
|
||||||
|
copy_message(uid,dest_folder)
|
||||||
|
delete_message(uid)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def append(folder,message,flags)
|
||||||
|
begin
|
||||||
|
@imap.append(folder,message,flags)
|
||||||
|
rescue Exception => e
|
||||||
|
raise e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
91
lib/imap_message.rb
Executable file
91
lib/imap_message.rb
Executable file
|
@ -0,0 +1,91 @@
|
||||||
|
require 'net/imap'
|
||||||
|
|
||||||
|
module ImapMessageModule
|
||||||
|
|
||||||
|
class IMAPAddress
|
||||||
|
|
||||||
|
attr_accessor :name,:mailbox,:host
|
||||||
|
|
||||||
|
def initialize()
|
||||||
|
name = ""
|
||||||
|
mailbox = ""
|
||||||
|
host = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.from_address(addr)
|
||||||
|
a = IMAPAddress.new()
|
||||||
|
a.name = addr.name || ""
|
||||||
|
a.mailbox = addr.mailbox || ""
|
||||||
|
a.host = addr.host || ""
|
||||||
|
a
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_db
|
||||||
|
name + "#" + mailbox + "#" + host
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.parse(addr)
|
||||||
|
a = IMAPAddress.new()
|
||||||
|
f = addr.split("#")
|
||||||
|
a.name = f[0]
|
||||||
|
a.mailbox = f[1]
|
||||||
|
a.host = f[2]
|
||||||
|
a
|
||||||
|
end
|
||||||
|
|
||||||
|
def friendly
|
||||||
|
if name.empty?
|
||||||
|
mailbox + host
|
||||||
|
else
|
||||||
|
name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class IMAPMessage
|
||||||
|
|
||||||
|
@@fetch_attr = ['RFC822.HEADER', 'FLAGS', 'UID', 'RFC822.SIZE']
|
||||||
|
#@@fetch_attr = ['RFC822','FLAGS', 'UID', 'RFC822.SIZE']
|
||||||
|
|
||||||
|
# attr_accessor :envelope,:uid,:content_type,:size,:unseen,:from,:message_id,:to,:from,:subject,:date
|
||||||
|
#
|
||||||
|
# def initialize
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def self.fromImap(message)
|
||||||
|
# m = IMAPMessage.new
|
||||||
|
# envelope = message.attr['ENVELOPE']
|
||||||
|
# m.envelope = envelope
|
||||||
|
# m.message_id = envelope.message_id
|
||||||
|
# m.date = envelope.date
|
||||||
|
# m.subject = envelope.subject
|
||||||
|
# m.uid = message.attr['UID']
|
||||||
|
# #content_type = m.attr['BODYSTRUCTURE'].multipart? ? 'multipart' : 'text'
|
||||||
|
# m.content_type = message.attr['BODYSTRUCTURE'].media_type.downcase
|
||||||
|
# m.size = message.attr['RFC822.SIZE']
|
||||||
|
# m.unseen = !(message.attr['FLAGS'].member? :Seen)
|
||||||
|
# m.from = IMAPAddress.from_address(envelope.from[0])
|
||||||
|
# m.to = IMAPAddress.from_address(envelope.to[0])
|
||||||
|
# m
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
def self.fetch_attr
|
||||||
|
@@fetch_attr
|
||||||
|
end
|
||||||
|
#
|
||||||
|
# def from_to_db
|
||||||
|
# from.to_db
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# def to_to_db
|
||||||
|
# to.to_db
|
||||||
|
# end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
25
lib/imap_session.rb
Executable file
25
lib/imap_session.rb
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
require 'net/imap'
|
||||||
|
require 'imap_mailbox'
|
||||||
|
|
||||||
|
module ImapSessionModule
|
||||||
|
|
||||||
|
def open_imap_session
|
||||||
|
begin
|
||||||
|
@mailbox ||= ImapMailboxModule::IMAPMailbox.new(logger,$defaults["imap_debug"])
|
||||||
|
@mailbox.connect(@current_user.servers.primary_for_imap,@current_user.login, @current_user.get_cached_password(session))
|
||||||
|
rescue Exception => ex
|
||||||
|
redirect_to :controller => 'internal', :action => 'loginfailure'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def close_imap_session
|
||||||
|
return if @mailbox.nil? or not(@mailbox.connected)
|
||||||
|
@mailbox.disconnect
|
||||||
|
@mailbox = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_imap_folder
|
||||||
|
@mailbox.set_folder(@current_folder.full_name) if not @current_folder.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
114
lib/mail_plugin_extension.rb
Executable file
114
lib/mail_plugin_extension.rb
Executable file
|
@ -0,0 +1,114 @@
|
||||||
|
require 'iconv'
|
||||||
|
|
||||||
|
module Mail
|
||||||
|
|
||||||
|
class Message
|
||||||
|
|
||||||
|
def decoded_and_charseted
|
||||||
|
begin
|
||||||
|
if not charset.upcase == 'UTF-8'
|
||||||
|
charset.nil? ? source_charset = $defaults["msg_unknown_charset"] : source_charset = charset
|
||||||
|
charseted = Iconv.iconv("UTF-8",source_charset,decoded).first
|
||||||
|
else
|
||||||
|
charseted = decoded
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
decoded
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Part
|
||||||
|
|
||||||
|
attr_accessor :idx,:parent_id
|
||||||
|
|
||||||
|
def isImage?
|
||||||
|
not (content_type =~ /^image/).nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def isText?
|
||||||
|
not (content_type =~ /^text\/plain/).nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def isHtml?
|
||||||
|
not (content_type =~ /^text\/html/).nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def getSize
|
||||||
|
body.raw_source.size
|
||||||
|
end
|
||||||
|
|
||||||
|
def decoded_and_charseted
|
||||||
|
begin
|
||||||
|
if not charset.upcase == 'UTF-8'
|
||||||
|
charset.nil? ? source_charset = $defaults["msg_unknown_charset"] : source_charset = charset
|
||||||
|
charseted = Iconv.iconv("UTF-8",source_charset,decoded).first
|
||||||
|
else
|
||||||
|
charseted = decoded
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
decoded
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
class Field
|
||||||
|
def charseted
|
||||||
|
begin
|
||||||
|
if value =~ /\=\?([\w\-]+)\?/
|
||||||
|
source_charset = $1
|
||||||
|
if source_charset.upcase == 'UTF-8'
|
||||||
|
return decoded
|
||||||
|
end
|
||||||
|
else
|
||||||
|
source_charset = $defaults["msg_unknown_charset"]
|
||||||
|
end
|
||||||
|
Iconv.iconv("UTF-8",source_charset,decoded).first
|
||||||
|
rescue
|
||||||
|
decoded
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Address
|
||||||
|
def charseted
|
||||||
|
begin
|
||||||
|
if value =~ /\=\?([\w\-]+)\?/
|
||||||
|
source_charset = $1
|
||||||
|
if source_charset.upcase == 'UTF-8'
|
||||||
|
return decoded
|
||||||
|
end
|
||||||
|
else
|
||||||
|
source_charset = $defaults["msg_unknown_charset"]
|
||||||
|
end
|
||||||
|
Iconv.iconv("UTF-8",source_charset,decoded).first
|
||||||
|
rescue
|
||||||
|
decoded
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Part
|
||||||
|
def filename_charseted
|
||||||
|
begin
|
||||||
|
if content_type =~ /\=\?([\w\-]+)\?/
|
||||||
|
source_charset = $1
|
||||||
|
if source_charset.upcase == 'UTF-8'
|
||||||
|
return filename
|
||||||
|
end
|
||||||
|
else
|
||||||
|
source_charset = $defaults["msg_unknown_charset"]
|
||||||
|
end
|
||||||
|
Iconv.iconv("UTF-8",source_charset,filename).first
|
||||||
|
rescue
|
||||||
|
filename
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,241 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Ruby on Rails: Welcome aboard</title>
|
|
||||||
<style type="text/css" media="screen">
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
padding: 0;
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
|
|
||||||
font-size: 13px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 28px;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {color: #03c}
|
|
||||||
a:hover {
|
|
||||||
background-color: #03c;
|
|
||||||
color: white;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#page {
|
|
||||||
background-color: #f0f0f0;
|
|
||||||
width: 750px;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
float: left;
|
|
||||||
background-color: white;
|
|
||||||
border: 3px solid #aaa;
|
|
||||||
border-top: none;
|
|
||||||
padding: 25px;
|
|
||||||
width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebar {
|
|
||||||
float: right;
|
|
||||||
width: 175px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#footer {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
#header, #about, #getting-started {
|
|
||||||
padding-left: 75px;
|
|
||||||
padding-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#header {
|
|
||||||
background-image: url("assets/rails.png");
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: top left;
|
|
||||||
height: 64px;
|
|
||||||
}
|
|
||||||
#header h1, #header h2 {margin: 0}
|
|
||||||
#header h2 {
|
|
||||||
color: #888;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#about h3 {
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#about-content {
|
|
||||||
background-color: #ffd;
|
|
||||||
border: 1px solid #fc0;
|
|
||||||
margin-left: -55px;
|
|
||||||
margin-right: -10px;
|
|
||||||
}
|
|
||||||
#about-content table {
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-size: 11px;
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
#about-content td {
|
|
||||||
padding: 10px;
|
|
||||||
padding-top: 3px;
|
|
||||||
padding-bottom: 3px;
|
|
||||||
}
|
|
||||||
#about-content td.name {color: #555}
|
|
||||||
#about-content td.value {color: #000}
|
|
||||||
|
|
||||||
#about-content ul {
|
|
||||||
padding: 0;
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#about-content.failure {
|
|
||||||
background-color: #fcc;
|
|
||||||
border: 1px solid #f00;
|
|
||||||
}
|
|
||||||
#about-content.failure p {
|
|
||||||
margin: 0;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#getting-started {
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
margin-top: 25px;
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
#getting-started h1 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
#getting-started h2 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: normal;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
#getting-started ol {
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
#getting-started li {
|
|
||||||
font-size: 18px;
|
|
||||||
color: #888;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
#getting-started li h2 {
|
|
||||||
margin: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 18px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
#getting-started li p {
|
|
||||||
color: #555;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#sidebar ul {
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
#sidebar ul h3 {
|
|
||||||
margin-top: 25px;
|
|
||||||
font-size: 16px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
#sidebar li {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
#sidebar ul.links li {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filename {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<script type="text/javascript">
|
|
||||||
function about() {
|
|
||||||
info = document.getElementById('about-content');
|
|
||||||
if (window.XMLHttpRequest)
|
|
||||||
{ xhr = new XMLHttpRequest(); }
|
|
||||||
else
|
|
||||||
{ xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
|
|
||||||
xhr.open("GET","rails/info/properties",false);
|
|
||||||
xhr.send("");
|
|
||||||
info.innerHTML = xhr.responseText;
|
|
||||||
info.style.display = 'block'
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="page">
|
|
||||||
<div id="sidebar">
|
|
||||||
<ul id="sidebar-items">
|
|
||||||
<li>
|
|
||||||
<h3>Browse the documentation</h3>
|
|
||||||
<ul class="links">
|
|
||||||
<li><a href="http://guides.rubyonrails.org/">Rails Guides</a></li>
|
|
||||||
<li><a href="http://api.rubyonrails.org/">Rails API</a></li>
|
|
||||||
<li><a href="http://www.ruby-doc.org/core/">Ruby core</a></li>
|
|
||||||
<li><a href="http://www.ruby-doc.org/stdlib/">Ruby standard library</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="content">
|
|
||||||
<div id="header">
|
|
||||||
<h1>Welcome aboard</h1>
|
|
||||||
<h2>You’re riding Ruby on Rails!</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="about">
|
|
||||||
<h3><a href="rails/info/properties" onclick="about(); return false">About your application’s environment</a></h3>
|
|
||||||
<div id="about-content" style="display: none"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="getting-started">
|
|
||||||
<h1>Getting started</h1>
|
|
||||||
<h2>Here’s how to get rolling:</h2>
|
|
||||||
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
<h2>Use <code>rails generate</code> to create your models and controllers</h2>
|
|
||||||
<p>To see all available options, run it without parameters.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<h2>Set up a default route and remove <span class="filename">public/index.html</span></h2>
|
|
||||||
<p>Routes are set up in <span class="filename">config/routes.rb</span>.</p>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<h2>Create your database</h2>
|
|
||||||
<p>Run <code>rake db:create</code> to create your database. If you're not using SQLite (the default), edit <span class="filename">config/database.yml</span> with your username and password.</p>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="footer"> </div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Loading…
Reference in a new issue