android kotlin 呼叫(發起)email app

好多種版本, 終於找到可以用的

  • 第一種寫法(比較適合寫慣java的老師傅)
val email_intent =  Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
    email_intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    email_intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("your@email.com"))
    email_intent.putExtra(Intent.EXTRA_SUBJECT, "問題回報");
    email_intent.putExtra(Intent.EXTRA_TEXT,"");
    try {
      startActivity(Intent.createChooser(email_intent, "請選擇郵件軟體"))
    }catch (e:ActivityNotFoundException){
      Toast.makeText(myactivity, "請確認並設定好郵件收發軟體", Toast.LENGTH_LONG).show()
    }
  • 第二種寫法
val email_intent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:")).apply {
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
    putExtra(Intent.EXTRA_EMAIL, arrayOf("your@email.com"))
    putExtra(Intent.EXTRA_SUBJECT, "問題回報")
    putExtra(Intent.EXTRA_TEXT, "")
  }
  try {
    startActivity(Intent.createChooser(email_intent, "請選擇郵件軟體"))
  } catch ( ex: ActivityNotFoundException) {
    Toast.makeText(myactivity, "請確認並設定好郵件收發軟體", Toast.LENGTH_LONG).show()
  }

使用restic做離線備份, 充滿儀式感,老闆也開心

前陣子發現restic備份的好處, 尤其拿來當離線備份.

IT同事進行離線備份時, 有意無意被老闆路過, 看到滿滿備份畫面咻咻跑來跑去, 充滿了儀式感.
老闆開心, IT同仁也有成就感.


restic指令備份, 不夠自動化, 為了讓IT同事做少少的工作, 又讓IT同事與其他路過的同事覺得好專業, 因此寫了簡單的restic backup script , 可以協助掛載來源目錄, 掛載後,進行restic備份.

檔案請到這裡下載, 下載後請看readme.md檔案

centos 安裝dkim並且自動產生相關文件

先前寫了一篇centos7安裝opendkim+postfix 這只是單一網域, 若要多個網域,實在是很麻煩

google爬文爬到一篇文章,有神人寫了自動產生相關文件的shell script , 我稍微修改一下, 就能很方便產生相關文件.

  • 安裝dkim套件
#centos 7
yum install opendkim
#centos 8 , rocky linux 8
yum install opendkim opendkim-tools
  • 修改 opendkim.conf
    把Mode 改成 sv

postfix寄信認證改用dovecot

一直以來我都讓postfix使用 sasl 方式處裡寄信認證, 但是連結到多網域主控伺服器的時候, 就會出錯, 很麻煩.
經過測試 dovecot 可以使用多組 userdb , 與passdb , 達到一個mail server 支援多個ldap網域主控.

當然也能省下一個sasl的service

  • 修改dovecort的 conf.d/10-master.conf
service auth {
...
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    # Assuming the default Postfix user and group
    user = postfix
    group = postfix
  }
  ...
}

#以下設定為了相容outlook系統
auth_mechanisms = plain login
  • 修改postfix的main.cf
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth

# On Debian Wheezy path must be relative and queue_directory defined
#queue_directory = /var/spool/postfix

# and the common settings to enable SASL:
smtpd_sasl_auth_enable = yes
  • 修改postfix的master.cf
submission inet n - n - - smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_sasl_security_options=noanonymous
  -o smtpd_sasl_local_domain=$myhostname
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_sender_login_maps=hash:/etc/postfix/virtual
  -o smtpd_sender_restrictions=reject_sender_login_mismatch
 ...

參考:

https://doc.dovecot.org/configuration_manual/howto/postfix_and_dovecot_sasl/

移除windows 10或以後版本,路徑檔案超過260個字元

這真是很令人頭疼的問題, 預設是不能超過260個字元, 微軟說windows 10 1607版本後面,可以自行調整開啟長檔名的功能

從 Windows 10 1607 版開始,已從一般 Win32 檔案和目錄函式中移除MAX_PATH限制。 不過,您必須加入宣告新的行為
  • 個人主機

修改reg

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"LongPathsEnabled"=dword:00000001

或是改本機原則

Computer Configuration > Administrative Templates > System > Filesystem > Enable Win32 long paths
  • 公司主機(網域主控群組原則)
  1. AD: windows 2012R2或之前的才需要這樣做
  2. 安裝最新版windows 10 管理範本
    https://www.microsoft.com/en-us/download/103124
  3. 將windows 10管理範本複製到目前網域的群組原則
    複製  C:\Program Files (x86)\Microsoft Group Policy\Windows 10 and Windows Server 2016\PolicyDefinitions

    SYSVOL\domain\Policies\PolicyDefinitions
  4. 重新執行群組原則設定, 就能看到 Enable win32 long paths

android kotlin coroutines

import kotlinx.coroutines.*
fun main() {
   repeat(3) {
        GlobalScope.launch {
            println("Hi from ${Thread.currentThread()}")
        }
    }
}
  • 非同步
import kotlinx.coroutines.*
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

val formatter = DateTimeFormatter.ISO_LOCAL_TIME
val time = { formatter.format(LocalDateTime.now()) }

suspend fun getValue(): Double {
    println("entering getValue() at ${time()}")
    delay(3000)
    println("leaving getValue() at ${time()}")
    return Math.random()
}

fun main() {
    runBlocking {
        val num1 = getValue()
        val num2 = getValue()
        println("result of num1 + num2 is ${num1 + num2}")
    }
}

同步

import kotlinx.coroutines.*
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

val formatter = DateTimeFormatter.ISO_LOCAL_TIME
val time = { formatter.format(LocalDateTime.now()) }

suspend fun getValue(): Double {
    println("entering getValue() at ${time()}")
    delay(3000)
    println("leaving getValue() at ${time()}")
    return Math.random()
}

fun main() {
    runBlocking {
        val num1 = async { getValue() }
        val num2 = async { getValue() }
        println("result of num1 + num2 is ${num1.await() + num2.await()}")
    }
}

job

val job: Job = GlobalScope.launch(Dispatchers.Main) {
    // launch coroutine in the main thread
    for (i in 10 downTo 1) { // countdown from 10 to 1
        textView.text = "count down $i ..." // update text
        delay(1000) // wait half a second
    }
    textView.text = "Done!"
}
job.cancel()
1 ... 11 12 13 14 15 ... 58