├── .Rbuildignore ├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ └── test-coverage.yaml ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── NAMESPACE ├── NEWS.md ├── R ├── AND.R ├── OR.R ├── R6.R ├── add-flags-int.R ├── adjust-folder-name.R ├── adjust_repeated_filenames.R ├── before.R ├── check-args.R ├── clean-fetch-results.R ├── clean-msg-text.R ├── config-con-handle-and-params.R ├── configure-imap.R ├── copy-msg-int.R ├── create-folder-int.R ├── decode-base64-text-if-needed.R ├── decode-mime-header.R ├── decode-mime-text.R ├── decode-quoted-printable-header.R ├── decode-quoted-printable-text.R ├── define-searchrequest-custom.R ├── define-searchrequest-date.R ├── define-searchrequest-flag.R ├── define-searchrequest-period.R ├── define-searchrequest-size.R ├── define-searchrequest-string.R ├── define-searchrequest-within.R ├── delete-msg-int-new.R ├── delete-msg-int.R ├── esearch-count-int.R ├── esearch-max-id-int.R ├── esearch-min-id-int.R ├── examine-folder-int.R ├── execute-attachment-fetch.R ├── execute-complementary-operations.R ├── execute-fetch-loop.R ├── execute-search.R ├── expunge-int.R ├── extract-MIME-level-and-filenames.R ├── fetch-attachments-int.R ├── fetch-attachments-list-int.R ├── fetch-body-int.R ├── fetch-header-int.R ├── fetch-metadata-int.R ├── fetch-text-int.R ├── fix-search-stripping.R ├── flag.R ├── get-attachments-int.R ├── has-attachment.R ├── larger-than.R ├── list-attachments.R ├── list-flags-int.R ├── list-mail-folders-int.R ├── list-server-capabilities-int.R ├── metadata-options.R ├── modify-con-handle.R ├── move-msg-int.R ├── older-than.R ├── on.R ├── pipe.R ├── remove-flags-int.R ├── rename-folder-int.R ├── replace-flags-int.R ├── response-error-handling.R ├── search-before-int.R ├── search-flag-int.R ├── search-int.R ├── search-larger-than-int.R ├── search-older-than-int.R ├── search-on-int.R ├── search-period-int.R ├── search-sent-before-int.R ├── search-sent-on-int.R ├── search-sent-period-int.R ├── search-sent-since-int.R ├── search-since-int.R ├── search-smaller-than-int.R ├── search-string-int.R ├── search-younger-than-int.R ├── select-folder-int.R ├── sent-before.R ├── sent-on.R ├── sent-since.R ├── serialize-filename.R ├── since.R ├── smaller-than.R ├── string.R ├── younger-than.R └── zzz.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── docs ├── apple-touch-icon-120x120.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon.png ├── articles │ ├── basics.html │ ├── code_migration.html │ ├── figures │ │ └── xoauth │ │ │ ├── step1_1.png │ │ │ ├── step1_1x.png │ │ │ ├── step2_1x.png │ │ │ ├── step2_2x.png │ │ │ ├── step2_3.png │ │ │ ├── step2_x1.png │ │ │ ├── step2_x2.png │ │ │ ├── step2_x3x.png │ │ │ ├── step2_x4.png │ │ │ ├── step2_x5.png │ │ │ └── step2_x6.png │ ├── index.html │ └── xoauth2.0.html ├── authors.html ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html ├── link.svg ├── logo.png ├── news │ └── index.html ├── pkgdown.js ├── pkgdown.yml └── reference │ ├── AND.html │ ├── ImapCon.html │ ├── OR.html │ ├── before.html │ ├── configure_imap.html │ ├── decode_mime_header.html │ ├── figures │ ├── aol1.png │ ├── aol2.png │ ├── aol3.png │ ├── gmail1.png │ ├── logo.png │ ├── yahoo1.png │ ├── yahoo2.png │ └── yahoo3.png │ ├── flag.html │ ├── index.html │ ├── larger_than.html │ ├── list_attachments.html │ ├── mRpostman-package.html │ ├── metadata_options.html │ ├── older_than.html │ ├── on.html │ ├── pipe.html │ ├── sent_before.html │ ├── sent_on.html │ ├── sent_since.html │ ├── since.html │ ├── smaller_than.html │ ├── string.html │ └── younger_than.html ├── inst └── CITATION ├── mRpostman.Rproj ├── man ├── AND.Rd ├── ImapCon.Rd ├── OR.Rd ├── before.Rd ├── clean_msg_text.Rd ├── configure_imap.Rd ├── decode_mime_header.Rd ├── figures │ ├── aol1.png │ ├── aol2.png │ ├── aol3.png │ ├── gmail1.png │ ├── logo.png │ ├── yahoo1.png │ ├── yahoo2.png │ └── yahoo3.png ├── flag.Rd ├── larger_than.Rd ├── list_attachments.Rd ├── mRpostman-package.Rd ├── metadata_options.Rd ├── older_than.Rd ├── on.Rd ├── pipe.Rd ├── sent_before.Rd ├── sent_on.Rd ├── sent_since.Rd ├── since.Rd ├── smaller_than.Rd ├── string.Rd └── younger_than.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico └── vignettes ├── .gitignore ├── basics.Rmd ├── code_migration.Rmd ├── figures ├── basics │ ├── attach1.png │ ├── attach2.png │ └── fetchbody.png └── xoauth │ ├── step1_1.png │ ├── step1_1x.png │ ├── step1_2.png │ ├── step2_1.png │ ├── step2_1x.png │ ├── step2_2.png │ ├── step2_2x.png │ ├── step2_3.png │ ├── step2_4.png │ ├── step2_x1.png │ ├── step2_x2.png │ ├── step2_x3.png │ ├── step2_x3x.png │ ├── step2_x4.png │ ├── step2_x5.png │ └── step2_x6.png ├── xoauth2.0 └── xoauth2.0.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^_pkgdown\.yml$ 4 | ^docs$ 5 | ^pkgdown$ 6 | ^README\.Rmd$ 7 | ^cran-comments\.md$ 8 | ^NEWS\.md$ 9 | ^\.travis\.yml$ 10 | ^\.httr-oauth$ 11 | ^\.github$ 12 | ^codecov\.yml$ 13 | -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel-1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | R_KEEP_PKG_SOURCE: yes 30 | 31 | steps: 32 | - uses: actions/checkout@v3 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | http-user-agent: ${{ matrix.config.http-user-agent }} 40 | use-public-rspm: true 41 | 42 | - uses: r-lib/actions/setup-r-dependencies@v2 43 | with: 44 | extra-packages: any::rcmdcheck 45 | needs: check 46 | 47 | - uses: r-lib/actions/check-r-package@v2 48 | with: 49 | upload-snapshots: true 50 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - uses: r-lib/actions/setup-r-dependencies@v2 25 | with: 26 | extra-packages: any::covr 27 | needs: coverage 28 | 29 | - name: Test coverage 30 | run: | 31 | covr::codecov( 32 | quiet = FALSE, 33 | clean = FALSE, 34 | install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") 35 | ) 36 | shell: Rscript {0} 37 | 38 | - name: Show testthat output 39 | if: always() 40 | run: | 41 | ## -------------------------------------------------------------------- 42 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 43 | shell: bash 44 | 45 | - name: Upload test results 46 | if: failure() 47 | uses: actions/upload-artifact@v3 48 | with: 49 | name: coverage-test-failures 50 | path: ${{ runner.temp }}/package 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | docs 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | cache: packages 5 | warnings_are_errors: false #ignore warnings in osx 6 | 7 | matrix: 8 | include: 9 | - os: linux 10 | r: 11 | - release 12 | - devel 13 | env: R_CODECOV=true 14 | - os: osx 15 | osx_image: xcode12.2 16 | r: 17 | - release 18 | - devel 19 | #addons: 20 | # homebrew: 21 | # packages: 22 | # - libgit2 23 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: mRpostman 2 | Type: Package 3 | Title: An IMAP Client for R 4 | Version: 1.1.4 5 | Date: 2024-09-15 6 | Authors@R: c( 7 | person(given="Allan", family="Quadros", 8 | role = c("aut", "cre"), 9 | email = "allanvcq@gmail.com", 10 | comment = c(ORCID = "0000-0003-3250-5380")), 11 | person(given="Paul", family="Smith", 12 | role = c("ctb")), 13 | person(given="Kurt", family="Hornik", 14 | role = c("ctb")) 15 | ) 16 | Description: An easy-to-use IMAP client that provides tools for message searching, 17 | selective fetching of message attributes, mailbox management, attachment extraction, 18 | and several other IMAP features, paving the way for e-mail data analysis in R. 19 | License: GPL-3 20 | Encoding: UTF-8 21 | Imports: curl, 22 | R6, 23 | stringr, 24 | stringi, 25 | magrittr, 26 | assertthat, 27 | base64enc, 28 | utils, 29 | rvest, 30 | xml2 31 | Depends: R (>= 3.1.0) 32 | URL: https://allanvc.github.io/mRpostman/ 33 | BugReports: https://github.com/allanvc/mRpostman/issues/ 34 | SystemRequirements: libcurl: libcurl-devel (rpm) or libcurl4-openssl-dev (deb) 35 | Suggests: knitr, rmarkdown 36 | VignetteBuilder: knitr 37 | RoxygenNote: 7.3.2 38 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export("%>%") 4 | export(AND) 5 | export(ImapCon) 6 | export(OR) 7 | export(before) 8 | export(clean_msg_text) 9 | export(configure_imap) 10 | export(decode_mime_header) 11 | export(flag) 12 | export(larger_than) 13 | export(list_attachments) 14 | export(metadata_options) 15 | export(older_than) 16 | export(on) 17 | export(sent_before) 18 | export(sent_on) 19 | export(sent_since) 20 | export(since) 21 | export(smaller_than) 22 | export(string) 23 | export(younger_than) 24 | importFrom(R6,R6Class) 25 | importFrom(magrittr,"%>%") 26 | -------------------------------------------------------------------------------- /R/AND.R: -------------------------------------------------------------------------------- 1 | #' Relational-operator-function to construct a custom search statement 2 | #' @param ... a combination of criteria constructor functions with its arguments. 3 | #' @param negate If \code{TRUE}, negates the search and seeks for 4 | #' "NOT search_criterion". Default is \code{FALSE}. 5 | #' @return A search string to be used as a \code{request} parameter in 6 | #' \code{ImapCon$search()} function. 7 | #' @family custom search 8 | #' @examples 9 | #' \dontrun{ 10 | #' # select folder & search 11 | #' con$select_folder(name = "INBOX") 12 | #' # search for messages SINCE "30-Ago-2019" AND SMALLER than 512KB. 13 | #' res <- con$search(request = AND(sent_since(date_char = "30-Ago-2019"), 14 | #' smaller_than(size = 512000))) 15 | #' } 16 | #' @export 17 | #' 18 | AND <- function(..., negate = FALSE) { 19 | # just a wrapper to paste 20 | 21 | # ... must be 2+ args 22 | argg <- list(...) 23 | 24 | assertthat::assert_that( 25 | length(argg) >= 2 26 | , msg='AND() requires two or more arguments.') 27 | 28 | assertthat::assert_that( 29 | is.logical(negate), 30 | msg='"negate" must be a logical.') 31 | 32 | # setting part of the search string 33 | 34 | if (!isTRUE(negate)) { 35 | out = paste0(paste(..., sep=' ')) # we'll already have parenthesis 36 | #... inside '...' args 37 | 38 | } else { 39 | out = paste0('NOT (', paste(..., sep = ' '), ')') 40 | 41 | } 42 | 43 | return(out) 44 | 45 | } 46 | -------------------------------------------------------------------------------- /R/OR.R: -------------------------------------------------------------------------------- 1 | #' @inherit AND 2 | #' @family custom search 3 | #' @examples 4 | #' \dontrun{ 5 | #' # select folder & search 6 | #' con$select_folder(name = "INBOX") 7 | #' # search for messages SINCE "30-Ago-2019" OR SMALLER than 512KB. 8 | #' res <- con$search(request = OR(sent_since(date_char = "30-Ago-2019"), 9 | #' smaller_than(size = 512000))) 10 | #' } 11 | #' @export 12 | #' 13 | OR <- function(..., negate = FALSE) { 14 | 15 | # ... must be 2+ args 16 | argg <- list(...) 17 | 18 | assertthat::assert_that( 19 | length(argg) >= 2 20 | , msg='OR() requires two or more arguments.') 21 | 22 | 23 | assertthat::assert_that( 24 | is.logical(negate), 25 | msg='"negate" must be a logical.') 26 | 27 | # setting number of OR's 28 | n_OR <- length(argg) - 1 29 | 30 | # setting part of the search string 31 | 32 | if (!isTRUE(negate)) { 33 | out = paste0(paste0(rep('OR', n_OR), collapse = ' '), ' ', paste(..., sep = ' ')) # we'll already have parenthesis 34 | #... inside '...' args 35 | 36 | } else { 37 | out = paste0('NOT (', paste0(rep('OR', n_OR), collapse = ' '), ' ', paste(..., sep = ' '), ')') 38 | 39 | } 40 | 41 | return(out) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /R/add-flags-int.R: -------------------------------------------------------------------------------- 1 | #' Add Flags to message(s) 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param flags_to_set A \code{character vector} containing one ore more flag 12 | #' names to add to the specified message ids. If the flag to be set is an 13 | #' system flag, such as \code{\\SEEN}, \code{\\ANSWERED}, the name should be 14 | #' preceded by two backslashes \code{\\}. 15 | #' @param mute A \code{logical}. Provides a confirmation message if the 16 | #' command is successfully executed. Default is \code{FALSE}. 17 | #' @param retries Number of attempts to connect and execute the command. 18 | #' Default is \code{1}. 19 | #' @noRd 20 | add_flags_int <- function(self, msg_id, use_uid, flags_to_set, mute, retries) { 21 | 22 | check_args(msg_id = msg_id, use_uid, flags_to_set = flags_to_set, 23 | mute = mute, 24 | retries = retries) 25 | 26 | retries <- as.integer(retries) 27 | 28 | url <- self$con_params$url 29 | 30 | # isolating the handle 31 | h <- self$con_handle 32 | 33 | # prepare flag and msg_id strings 34 | flags_string <- paste(flags_to_set, collapse = " ") 35 | 36 | msg_string = paste0(msg_id, collapse = ",") 37 | 38 | # setting customrequest 39 | if (isTRUE(use_uid)) { 40 | 41 | customrequest <- paste0("UID STORE ", msg_string, " +FLAGS ", "(", flags_string, ")") 42 | 43 | 44 | } else { 45 | 46 | customrequest <- paste0("STORE ", msg_string, " +FLAGS ", "(", flags_string, ")") 47 | 48 | } 49 | 50 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 51 | retries) 52 | 53 | # capture possible errors (in case of non-existent/allowed flags, curl does not assess the server response as an error) 54 | if (!is.null(response)) { 55 | error_check <- grepl(pattern = "^\\* NO ", x = rawToChar(response$headers)) # it will be on headers in this case 56 | if (isTRUE(error_check)) { 57 | stop(unlist(regmatches(rawToChar(response$headers), 58 | regexec("\\* NO (.*?)\r\n", 59 | rawToChar(response$headers))))[[2]]) 60 | } # if a flag "\flag" does not exist, it returns NULL (a regular error that we are used to) 61 | } 62 | 63 | if (!mute) { 64 | if (self$con_params$verbose) { 65 | Sys.sleep(0.01) 66 | } 67 | cat(paste0("\n::mRpostman: flag(s) successfuly added.")) # v0.3.2 68 | # using the folder name without any transformation 69 | } 70 | 71 | # handle sanitizing 72 | rm(h) 73 | 74 | # return(TRUE) 75 | return(msg_id) 76 | 77 | } 78 | -------------------------------------------------------------------------------- /R/adjust-folder-name.R: -------------------------------------------------------------------------------- 1 | #' Mail folder name checking and adjustment 2 | #' @param folder An character \code{vector} containing the folder name informed 3 | #' by the user inside ImapCon$select_folder(). 4 | #' @noRd 5 | adjust_folder_name <- function(folder) { 6 | 7 | # forcing folder to imap server accepted format 8 | folder <- gsub(" ", "%20", folder) 9 | 10 | folder_check <- grepl(pattern='^\\".*\\"$', x = folder) 11 | 12 | # we want to know if we have already added quotes 13 | 14 | if (!isTRUE(folder_check)) { 15 | folder <- paste0('"', folder, '"') 16 | } 17 | 18 | return(folder) 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /R/adjust_repeated_filenames.R: -------------------------------------------------------------------------------- 1 | #' Add sufix to filenames of a message if there is repetition 2 | #' @param filenames A character string with a message content. 3 | #' @noRd 4 | adjust_repeated_filenames = function(filenames){ 5 | 6 | # preparing the directory for saving 7 | duplicated_filenames <- duplicated(filenames) 8 | 9 | adjusted_filenames <- c() 10 | 11 | for (i in seq_along(filenames)) { 12 | if (duplicated_filenames[i]) { 13 | # the first one will never be repeated 14 | # .. so we assign i-1 15 | # f = paste0(filenames[i], "(", i, ")") 16 | f = paste0("(", i-1, ")", filenames[i]) 17 | adjusted_filenames <- c(adjusted_filenames, f) 18 | } else { 19 | adjusted_filenames <- c(adjusted_filenames, filenames[i]) 20 | } 21 | 22 | } 23 | 24 | return(adjusted_filenames) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /R/before.R: -------------------------------------------------------------------------------- 1 | #' Criterion constructor function to be combined in a custom search statement 2 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @return A search string to be used as a \code{request} parameter in 8 | #' \code{ImapCon$search()} function. 9 | #' @family custom search 10 | #' @examples 11 | #' \dontrun{ 12 | #' # select folder & search 13 | #' con$select_folder(name = "INBOX") 14 | #' # search for messages BEFORE "17-Apr-2019" AND NOT SMALLER than 512KB. 15 | #' res <- con$search(request = AND(before(date_char = "17-Apr-2019"), 16 | #' smaller_than(size = 512000, negate = TRUE))) 17 | #' } 18 | #' @export 19 | #' 20 | before <- function(date_char, negate = FALSE) { 21 | 22 | 23 | check_args(date_char, negate) 24 | 25 | # setting part of the search string 26 | 27 | if (!isTRUE(negate)) { 28 | out = paste0('(BEFORE ', date_char, ')') 29 | 30 | } else { 31 | out = paste0('(NOT (BEFORE ', date_char, '))') 32 | 33 | } 34 | 35 | return(out) 36 | 37 | } 38 | -------------------------------------------------------------------------------- /R/clean-fetch-results.R: -------------------------------------------------------------------------------- 1 | #' Clean message's results 2 | #' @param msg_text A character string with a message content. 3 | #' @noRd 4 | clean_fetch_results <- function(msg_text, metadata_attribute = NULL, attachment_fetch = FALSE) { 5 | 6 | 7 | pattern1 = "\\* \\d+ FETCH.*BODY.*\\{\\d+\\}\r\n" 8 | # result <- stringr::str_remove(string = msg_text, pattern = pattern1) 9 | result <- gsub(pattern1, "", msg_text, ignore.case = TRUE, useBytes = TRUE) 10 | 11 | pattern2 = "\\)\r\n[A-Z]\\d+ OK Success\r\n" 12 | # result <- stringr::str_remove(string = result, pattern = pattern2) 13 | result <- gsub(pattern2, "", result, ignore.case = TRUE, useBytes = TRUE) 14 | 15 | pattern3 = "\\)\r\n[A-Z]\\d+ OK FETCH completed.\r\n" #MS Exchange and yandex 16 | # result <- stringr::str_remove(string = result, pattern = pattern3) 17 | result <- gsub(pattern3, "", result, ignore.case = TRUE, useBytes = TRUE) 18 | 19 | # attachments 20 | pattern4 = "\\)\r\n[A-Z]\\d+ OK FETCH completed\r\n" #MS Exchange 21 | # result <- stringr::str_remove(string = result, pattern = pattern3) 22 | result <- gsub(pattern4, "", result, ignore.case = TRUE, useBytes = TRUE) 23 | 24 | pattern5 = "\r\n UID \\d+ FLAGS \\(.*\\)" #MS Exchange # important for attachments fetching 25 | # result <- stringr::str_remove(string = result, pattern = pattern3) 26 | result <- gsub(pattern5, "", result, ignore.case = TRUE, useBytes = TRUE) 27 | 28 | # pattern5 = "\r\n \\d+ FLAGS \\(.*\\)" #MS Exchange 29 | # # result <- stringr::str_remove(string = result, pattern = pattern3) 30 | # result <- gsub(pattern5, "", result, ignore.case = TRUE) 31 | 32 | 33 | if (!is.null(metadata_attribute) && (!any(metadata_attribute == "UID" || metadata_attribute == "uid"))) { 34 | pattern6 = "UID \\d+$| UID \\d+$" 35 | # result <- stringr::str_remove(string = result, pattern = pattern2) 36 | result <- gsub(pattern6, "", result, ignore.case = TRUE, useBytes = TRUE) 37 | } 38 | 39 | pattern7 = "^\\* \\d+ FETCH \\(" # important for fetch_metadata() 40 | result <- gsub(pattern7, "", result, ignore.case = TRUE, useBytes = TRUE) 41 | 42 | if (isTRUE(attachment_fetch)) { # in order to not have problem with fetcH_body/text + get_attachments() combo 43 | pattern8 = "==\r\n FLAGS \\((.*?)\\)|=\r\n FLAGS \\((.*?)\\)" # important for fetch_attachments with use_uid = FALSE - it returns the msg flags after the attachment part on Office 365 44 | result <- gsub(pattern8, "", result, ignore.case = TRUE, useBytes = TRUE) 45 | } 46 | 47 | 48 | # note to self: base R functions like regmatches returns error in some cases 49 | # sub is too slow 50 | 51 | return(result) 52 | } 53 | -------------------------------------------------------------------------------- /R/configure-imap.R: -------------------------------------------------------------------------------- 1 | #' @title IMAP Connection Configuration 2 | #' @description Configure and create a new IMAP connection. 3 | #' @param url A character string containing the IMAP server address 4 | #' @param username A character string containing the username. 5 | #' @param password A character string containing the user's password. 6 | #' @param xoauth2_bearer A character string containing the oauth2 bearer token. 7 | #' @param use_ssl A logical indicating the use or not of Secure Sockets Layer 8 | #' encryption when connecting to the IMAP server. Default is \code{TRUE}. 9 | #' @param verbose If \code{FALSE}, mutes the flow of information between the 10 | #' server and the client. Default is \code{FALSE}. 11 | #' @param buffersize The size in bytes for the receive buffer. Default is 12 | #' 16000 bytes or 16kb, which means it will use the libcurl's default value. 13 | #' According to the libcurl's documentation, the maximum buffersize is 512kb 14 | #' (or 512000 bytes), but any number passed to \code{buffersize} is treated 15 | #' as a request, not an order. 16 | #' @param timeout_ms Time in milliseconds (ms) to wait for the execution or 17 | #' re-execution of a command. Default is 0, which means that no timeout limit is 18 | #' set. 19 | #' @param ... Further curl parameters (see \code{curl::curl_options}) that 20 | #' can be used with the IMAP protocol. Only for advanced users. 21 | #' @return A new `ImapCon` object. 22 | #' @export 23 | #' @examples 24 | #' \dontrun{ 25 | #' # w/ Plain authentication 26 | #' con <- configure_imap( 27 | #' url="imaps://outlook.office365.com", 28 | #' username="user@agency.gov.br", 29 | #' password=rstudioapi::askForPassword(), 30 | #' verbose = TRUE) 31 | #' 32 | #' # w/ OAuth2.0 authentication 33 | #' con <- configure_imap( 34 | #' url="imaps://outlook.office365.com", 35 | #' username="user@agency.gov.br", 36 | #' verbose = TRUE, 37 | #' xoauth2_bearer = "XX.Ya9...") 38 | #' } 39 | configure_imap <- function(url, 40 | username, 41 | password = NULL, 42 | xoauth2_bearer = NULL, 43 | use_ssl = TRUE, 44 | verbose = FALSE, 45 | buffersize = 16000, 46 | timeout_ms = 0, 47 | ...) { 48 | 49 | con <- ImapCon$new(url, 50 | username, 51 | password = password, 52 | xoauth2_bearer = xoauth2_bearer, 53 | use_ssl = use_ssl, 54 | verbose = verbose, 55 | buffersize = buffersize, 56 | timeout_ms = timeout_ms, 57 | ...) 58 | 59 | # fresh_connect is not supported anymore because the same handle is used during an 60 | # IMAP session. We let the handle manage the connection pool 61 | 62 | return(con) 63 | 64 | } 65 | -------------------------------------------------------------------------------- /R/copy-msg-int.R: -------------------------------------------------------------------------------- 1 | #' Copy message(s) between the selected folder and another one (INTERNAL HELPER) 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param to_folder A \code{character} string specifying the folder to which 12 | #' the messages will be copied. 13 | #' @param reselect A logical. If \code{TRUE}, calls 14 | #' \href{#method-select_folder}{\code{ImapCon$select_folder(name = to_folder)}} 15 | #' under the hood before returning the output. Default is \code{TRUE}. 16 | #' @param mute A \code{logical}. Provides a confirmation message if the 17 | #' command is successfully executed. Default is \code{FALSE}. 18 | #' @param retries Number of attempts to connect and execute the command. 19 | #' Default is \code{1}. 20 | #' @noRd 21 | copy_msg_int <- function(self, msg_id, use_uid, to_folder, reselect, mute, retries) { 22 | 23 | check_args(msg_id = msg_id, use_uid = use_uid, to_folder = to_folder, reselect = reselect, 24 | mute = mute, retries = retries) 25 | 26 | # quoting to guarantee folder with more than one name 27 | folder <- adjust_folder_name(self$con_params$folder) # there is a reselection in the end 28 | to_folder2 <- adjust_folder_name(to_folder) 29 | 30 | # forcing retries as an integer 31 | retries <- as.integer(retries) 32 | 33 | url <- self$con_params$url 34 | 35 | h <- self$con_handle 36 | 37 | # prepare msg_id strings 38 | msg_string = paste0(msg_id, collapse = ",") 39 | 40 | # customrequest parameter 41 | if (isTRUE(use_uid)) { 42 | 43 | customrequest <- paste0("UID COPY ", msg_string, " ", to_folder2) 44 | 45 | } else { 46 | 47 | customrequest <- paste0("COPY ", msg_string, " ", to_folder2) 48 | 49 | } 50 | 51 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 52 | retries) 53 | 54 | 55 | # reselecting 56 | if (isTRUE(reselect)) { 57 | # imapconf$folder = folder 58 | # select_folder(name = to_folder) 59 | reselected_folder <- select_folder_int(self, name = to_folder, mute = mute, retries = 0) # ok! v0.0.9 60 | } else { 61 | reselected_folder <- NULL 62 | } 63 | 64 | if (!mute) { 65 | if (self$con_params$verbose) { 66 | Sys.sleep(0.01) 67 | } 68 | cat(paste0("\n::mRpostman: message(s) copied")) # v0.3.2 69 | # using the folder name without any transformation 70 | } 71 | 72 | # will allow users to pipe more operations after adding flags 73 | return(list(msg_id = msg_id, folder = reselected_folder)) 74 | 75 | } 76 | -------------------------------------------------------------------------------- /R/create-folder-int.R: -------------------------------------------------------------------------------- 1 | #' @description Create a new mail folder (INTERNAL HELPER) 2 | #' @param name A string containing the name of the new mail folder to be 3 | #' created. 4 | #' @param mute A \code{logical}. Provides a confirmation message if the 5 | #' command is successfully executed. Default is \code{FALSE}. 6 | #' @param retries Number of attempts to connect and execute the command. 7 | #' Default is \code{1}. 8 | #' @noRd 9 | create_folder_int <- function(self, name, mute, retries) { 10 | 11 | check_args(name = name, mute = mute, retries = retries) # we have to pass 12 | #.. the argg as arg = arg, in order to the check_argg capture the names 13 | 14 | # forcing retries as an integer 15 | retries <- as.integer(retries) 16 | 17 | name2 <- adjust_folder_name(name) 18 | 19 | url <- self$con_params$url 20 | 21 | # isolating the handle 22 | h <- self$con_handle 23 | 24 | tryCatch({ 25 | curl::handle_setopt(h, customrequest = paste0('CREATE ', name2)) 26 | }, error = function(e){ 27 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapConf$new().") 28 | }) 29 | 30 | response <- tryCatch({ 31 | curl::curl_fetch_memory(url, handle = h) 32 | }, error = function(e){ 33 | # print(e$message) 34 | response_error_handling(e$message[1]) # returns NULL for operation timeout: try reconnection 35 | }) 36 | 37 | if(is.null(response)){ 38 | 39 | count_retries = 0 #the first try doesnt count 40 | 41 | # FORCE appending fresh_connect 42 | # curl::handle_setopt(handle = h, fresh_connect = TRUE) # parece que nao precisa, mas vamos deixar 43 | 44 | while (is.null(response) && count_retries < retries) { 45 | count_retries = count_retries + 1 46 | 47 | response <- tryCatch({ 48 | curl::curl_fetch_memory(url, handle = h) 49 | }, error = function(e){ 50 | # print(e$message) 51 | response_error_handling(e$message[1]) # returns NULL for operation timeout: try reconnection 52 | }) 53 | 54 | } 55 | 56 | if (is.null(response)) { 57 | 58 | stop('Request error: the server returned an error.') 59 | 60 | } else { # v0.3.2 61 | if (!mute) { 62 | 63 | if (self$con_params$verbose) { 64 | Sys.sleep(0.01) # wait for the end of the client-server conversation 65 | } 66 | 67 | cat(paste0("\n::mRpostman: folder ", '"', name, '"', " created.\n")) # v0.3.2 68 | 69 | } 70 | 71 | } 72 | 73 | } else { 74 | if (!mute) { 75 | 76 | if (self$con_params$verbose) { 77 | Sys.sleep(0.01) # wait for the end of the client-server conversation 78 | } 79 | 80 | cat(paste0("\n::mRpostman: folder ", '"', name, '"', " created.\n")) # v0.3.2 81 | 82 | } 83 | } 84 | 85 | invisible(TRUE) 86 | 87 | } 88 | -------------------------------------------------------------------------------- /R/decode-base64-text-if-needed.R: -------------------------------------------------------------------------------- 1 | #' @description Messages Results Decoding 2 | #' @param msg A \code{character} string with a message content. 3 | #' @noRd 4 | decode_base64_text_if_needed <- function(msg) { 5 | # to be used inside fetch_msg_text() - Headers and full msgs are fine, 6 | #.. except for the text part in full msgs 7 | check_result <- stringr::str_detect(string = msg, 8 | pattern = "(^[\\-\\-]+)|(???=}. 8 | #' The encoding can be of two types: "B" for "BASE64", or "Q" for quoted- 9 | #' printable content (Freed and Borentein, 1996). Besides the standard RFC 2047 10 | #' decoding, this function also enables users to decode content that does not 11 | #' strictly follow the \code{=????=} RFC 2047 12 | #' syntax, i.e. cases where only the encoded text part is present, such as the 13 | #' quoted-printable pattern in the string \code{"Estat=EDstica"} (Estatística, 14 | #' which is the equivalent word, in Portuguese, for Statistics). 15 | #' @references Moore, K. (1996), MIME (Multipurpose Internet Mail Extensions) Part 16 | #' Three: Message Header Extensions for Non-ASCII 17 | #' Text, RFC 2047, November 1996, https://tools.ietf.org/html/rfc2047. 18 | #' @references Freed, N., Borenstein, N. (1996), Multipurpose Internet Mail Extensions 19 | #' (MIME) Part One: Format of Internet Message Bodies, RFC 2045, November 1996, 20 | #' https://tools.ietf.org/html/rfc2045. 21 | #' @references Internal parts of this object, regarding the quoted printable type, 22 | #' were borrowed from https://github.com/hrbrmstr/hrbrmisc/blob/master/R/qp.r with 23 | #' slight modifications. 24 | #' @noRd 25 | decode_mime_text <- function(string) { 26 | 27 | # check if it is a character vector 28 | #check 29 | check_args(string = string) 30 | 31 | out <- c() 32 | for (i in seq_along(string)) { # "vectorized" 33 | 34 | 35 | content <- string[i] 36 | 37 | # first we need to test for b64 encoding 38 | # because the quoted-printable regex will also capture base64 encoded strings 39 | # but the contrary is not true 40 | if (grepl(pattern = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$", x = content)) { 41 | # sol: https://stackoverflow.com/questions/8571501/how-to-check-whether-a-string-is-base64-encoded-or-not 42 | decoded_string <- tryCatch({ 43 | rawToChar(base64enc::base64decode(content)) 44 | }, error = function(e) { 45 | content 46 | }) 47 | 48 | # } else if (grepl(pattern = "[\\x80-\\xff]", x = content)) { # assim reconhece direto sem precisar transformar!! 49 | } else if (grepl(pattern = "[\\x80-\\xD1\\x8F]", x = content)) { # assim reconhece direto sem precisar transformar!! 50 | decoded_string <- decode_quoted_printable_text(qp_encoded = content) 51 | 52 | } else { 53 | decoded_string <- content 54 | } 55 | 56 | out <- c(out, decoded_string) 57 | 58 | } 59 | 60 | return(out) 61 | 62 | } 63 | -------------------------------------------------------------------------------- /R/define-searchrequest-custom.R: -------------------------------------------------------------------------------- 1 | #' Define custom search request 2 | #' @param request A string directly specifying what to search or 3 | #' constructed by a combination of operators helper functions \code{\link{OR}} 4 | #' and \code{\link{AND}}, and criteria helper functions such as 5 | #' \code{\link{before}}, \code{\link{since}}, \code{\link{on}}, 6 | #' \code{\link{sent_before}}, \code{\link{sent_since}}, \code{\link{sent_on}}, 7 | #' \code{\link{flag}}, \code{\link{string}}, \code{\link{smaller_than}}, 8 | #' \code{\link{larger_than}}, \code{\link{younger_than}}, or 9 | #' \code{\link{younger_than}}. 10 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 11 | #' CRITERIA". Default is \code{FALSE}. 12 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 13 | #' presented as message's sequence numbers. A message sequence number is a 14 | #' message's relative position to the oldest message in the mailbox. It may 15 | #' change after deleting or moving messages. If a message is deleted, sequence 16 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 17 | #' performed using the \code{"UID"} or unique identifier, and results are 18 | #' presented as such. UIDs are always the same during the life cycle of a message. 19 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 20 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 21 | #' will condense the results: instead of writing down the whole sequences of messages' 22 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 23 | #' which decreases transmission costs. This argument can be used along with 24 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 25 | #' supports \code{ESEARCH} with 26 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 27 | #' @param handle A curl handle object. 28 | #' @noRd 29 | define_searchrequest_custom <- function(request, negate, use_uid, esearch, 30 | handle) { 31 | 32 | # esearch 33 | if (isTRUE(esearch)) { 34 | esearch_string = "RETURN () " 35 | } else { 36 | esearch_string = NULL 37 | } 38 | 39 | # use_uid 40 | if (isTRUE(use_uid)) { 41 | use_uid_string = "UID " 42 | } else { 43 | use_uid_string = NULL 44 | } 45 | 46 | # # by 47 | # if (by == "UID") { 48 | # by_string = "UID " 49 | # } else { 50 | # by_string = NULL 51 | # } 52 | 53 | # negate 54 | if (isTRUE(negate)) { 55 | negate_string = "NOT " 56 | } else { 57 | negate_string = NULL 58 | } 59 | 60 | customrequest = paste0(use_uid_string, "SEARCH ", esearch_string, negate_string, "(", request, ")") 61 | 62 | tryCatch({ 63 | curl::handle_setopt( 64 | handle = handle, 65 | customrequest = customrequest) 66 | }, error = function(e){ 67 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 68 | }) 69 | 70 | 71 | return(c(handle = handle, customrequest = customrequest)) 72 | 73 | } 74 | -------------------------------------------------------------------------------- /R/define-searchrequest-date.R: -------------------------------------------------------------------------------- 1 | #' Define date search request 2 | #' @inheritParams search_before 3 | #' @param operation The type of date operation, eg. \code{BEFORE}, \code{SINCE}, 4 | #' \code{ON}, and variations. 5 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 6 | #' "01-Apr-2019". We opted for not to use \code{Date} or \code{POSIX*} like 7 | #' objects, since IMAP servers use this unusual date format. 8 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 9 | #' CRITERIA". Default is \code{FALSE}. 10 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 11 | #' presented as message's sequence numbers. A message sequence number is a 12 | #' message's relative position to the oldest message in the mailbox. It may 13 | #' change after deleting or moving messages. If a message is deleted, sequence 14 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 15 | #' performed using the \code{"UID"} or unique identifier, and results are 16 | #' presented as such. UIDs are always the same during the life cycle of a message. 17 | #' @param flag Optional argument that sets one or more flags as an additional 18 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 19 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 20 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 21 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 22 | #' will condense the results: instead of writing down the whole sequences of messages' 23 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 24 | #' which decreases transmission costs. This argument can be used along with 25 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 26 | #' supports \code{ESEARCH} with 27 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 28 | #' @param handle A curl handle object. 29 | #' @noRd 30 | define_searchrequest_date <- function(operation, date_char, negate, use_uid, flag, 31 | esearch, handle) { 32 | 33 | # esearch 34 | if (isTRUE(esearch)) { 35 | esearch_string = "RETURN () " 36 | } else { 37 | esearch_string = NULL 38 | } 39 | 40 | # flag 41 | if (!is.null(flag)) { 42 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 43 | flag_string = paste0(flag_string, " ") 44 | } else { 45 | flag_string = NULL 46 | } 47 | 48 | # use_uid 49 | if (isTRUE(use_uid)) { 50 | use_uid_string = "UID " 51 | } else { 52 | use_uid_string = NULL 53 | } 54 | 55 | # negate 56 | if (isTRUE(negate)) { 57 | negate_string = "NOT " 58 | } else { 59 | negate_string = NULL 60 | } 61 | 62 | customrequest <- paste0(use_uid_string, "SEARCH ", esearch_string, flag_string, 63 | negate_string, operation, ' ', date_char) 64 | 65 | tryCatch({ 66 | curl::handle_setopt( 67 | handle = handle, 68 | customrequest = customrequest) 69 | }, error = function(e){ 70 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 71 | }) 72 | 73 | return(c(handle = handle, customrequest = customrequest)) 74 | } 75 | -------------------------------------------------------------------------------- /R/define-searchrequest-flag.R: -------------------------------------------------------------------------------- 1 | #' Define flag search request 2 | #' @param name A string containing one or more flags to search for. Use 3 | #' \href{#method-list_flags}{\code{ImapCon$list_flags()}} to list the flags 4 | #' in a selected mail folder. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 15 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 16 | #' will condense the results: instead of writing down the whole sequences of messages' 17 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 18 | #' which decreases transmission costs. This argument can be used along with 19 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 20 | #' supports \code{ESEARCH} with 21 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 22 | #' @param handle A curl handle object. 23 | #' @noRd 24 | define_searchrequest_flag <- function(name, negate, use_uid, esearch, handle) { 25 | 26 | # esearch 27 | if (isTRUE(esearch)) { 28 | esearch_string = "RETURN () " 29 | } else { 30 | esearch_string = NULL 31 | } 32 | 33 | # flag/name (especial) 34 | # if (!is.null(flag)) { 35 | flag_string <- paste(name, collapse = " ") #v0.9.0 (for more than one flag passed) 36 | flag_string = paste0(flag_string, "") # different here because flag is the main parameter of search 37 | # } else { 38 | # flag_string = NULL 39 | # } 40 | 41 | # use_uid 42 | if (isTRUE(use_uid)) { 43 | use_uid_string = "UID " 44 | } else { 45 | use_uid_string = NULL 46 | } 47 | 48 | # negate 49 | if (isTRUE(negate)) { 50 | negate_string = "NOT " 51 | } else { 52 | negate_string = NULL 53 | } 54 | 55 | customrequest <- paste0(use_uid_string, "SEARCH ", esearch_string, negate_string, 56 | flag_string) 57 | 58 | tryCatch({ 59 | curl::handle_setopt( 60 | handle = handle, 61 | customrequest = customrequest) 62 | }, error = function(e){ 63 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 64 | }) 65 | 66 | return(c(handle = handle, customrequest = customrequest)) 67 | } 68 | -------------------------------------------------------------------------------- /R/define-searchrequest-period.R: -------------------------------------------------------------------------------- 1 | #' Define date period search request 2 | #' @inheritParams search_period 3 | #' @param operation1 A character indicating the first argument 4 | #' (SINCE and variations) to the custom request. 5 | #' @param since_date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 6 | #' "01-Apr-2019". We opted for not to use \code{Date} or \code{POSIX*} like 7 | #' objects, since IMAP servers use this unusual date format. 8 | #' @param operation2 A character indicating the first argument 9 | #' (BEFORE and variations) to the custom request. 10 | #' @param before_date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 11 | #' "01-Apr-2019". We opted for not to use \code{Date} or \code{POSIX*} like 12 | #' objects, since IMAP servers use this unusual date format. 13 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 14 | #' CRITERIA". Default is \code{FALSE}. 15 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 16 | #' presented as message's sequence numbers. A message sequence number is a 17 | #' message's relative position to the oldest message in the mailbox. It may 18 | #' change after deleting or moving messages. If a message is deleted, sequence 19 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 20 | #' performed using the \code{"UID"} or unique identifier, and results are 21 | #' presented as such. UIDs are always the same during the life cycle of a message. 22 | #' @param flag Optional argument that sets one or more flags as an additional 23 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 24 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 25 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 26 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 27 | #' will condense the results: instead of writing down the whole sequences of messages' 28 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 29 | #' which decreases transmission costs. This argument can be used along with 30 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 31 | #' supports \code{ESEARCH} with 32 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 33 | #' @param handle A curl handle object. 34 | #' @noRd 35 | define_searchrequest_period <- function(operation1, since_date_char, operation2, 36 | before_date_char, negate, use_uid, flag, 37 | esearch, handle) { 38 | 39 | # esearch 40 | if (isTRUE(esearch)) { 41 | esearch_string = "RETURN () " 42 | } else { 43 | esearch_string = NULL 44 | } 45 | 46 | # flag 47 | if (!is.null(flag)) { 48 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 49 | flag_string = paste0(flag_string, " ") 50 | } else { 51 | flag_string = NULL 52 | } 53 | 54 | # use_uid 55 | if (isTRUE(use_uid)) { 56 | use_uid_string = "UID " 57 | } else { 58 | use_uid_string = NULL 59 | } 60 | 61 | # negate 62 | if (isTRUE(negate)) { 63 | negate_string = "NOT " 64 | } else { 65 | negate_string = NULL 66 | } 67 | 68 | customrequest <- paste0(use_uid_string, "SEARCH ", esearch_string, flag_string, 69 | negate_string, "(", operation1, ' ', since_date_char, ' ', 70 | operation2, ' ', before_date_char, ")") 71 | 72 | tryCatch({ 73 | curl::handle_setopt( 74 | handle = handle, 75 | customrequest = customrequest) 76 | }, error = function(e){ 77 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 78 | }) 79 | 80 | return(c(handle = handle, customrequest = customrequest)) 81 | } 82 | -------------------------------------------------------------------------------- /R/define-searchrequest-size.R: -------------------------------------------------------------------------------- 1 | #' Define size search request 2 | #' @inheritParams search_period 3 | #' @param operation A character indicating which size operation to execute, 4 | #' \code{SMALLER} or \code{LARGER} than. 5 | #' @param size An integer specifying the number of seconds to be used as 6 | #' search criterion. 7 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 8 | #' CRITERIA". Default is \code{FALSE}. 9 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 10 | #' presented as message's sequence numbers. A message sequence number is a 11 | #' message's relative position to the oldest message in the mailbox. It may 12 | #' change after deleting or moving messages. If a message is deleted, sequence 13 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 14 | #' performed using the \code{"UID"} or unique identifier, and results are 15 | #' presented as such. UIDs are always the same during the life cycle of a message. 16 | #' @param flag Optional argument that sets one or more flags as an additional 17 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 18 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 19 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 20 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 21 | #' will condense the results: instead of writing down the whole sequences of messages' 22 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 23 | #' which decreases transmission costs. This argument can be used along with 24 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 25 | #' supports \code{ESEARCH} with 26 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 27 | #' @param handle A curl handle object. 28 | #' 29 | #' @noRd 30 | define_searchrequest_size <- function(operation, size, negate, use_uid, flag, esearch, 31 | handle) { 32 | 33 | # esearch 34 | if (isTRUE(esearch)) { 35 | esearch_string = "RETURN () " 36 | } else { 37 | esearch_string = NULL 38 | } 39 | 40 | # flag 41 | if (!is.null(flag)) { 42 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 43 | flag_string = paste0(flag_string, " ") 44 | } else { 45 | flag_string = NULL 46 | } 47 | 48 | # use_uid 49 | if (isTRUE(use_uid)) { 50 | use_uid_string = "UID " 51 | } else { 52 | use_uid_string = NULL 53 | } 54 | 55 | # # by 56 | # if (by == "UID") { 57 | # by_string = "UID " 58 | # } else { 59 | # by_string = NULL 60 | # } 61 | 62 | # negate 63 | if (isTRUE(negate)) { 64 | negate_string = "NOT " 65 | } else { 66 | negate_string = NULL 67 | } 68 | 69 | customrequest <- paste0(use_uid_string, "SEARCH ", esearch_string, flag_string, 70 | negate_string, operation, ' ', size) 71 | 72 | tryCatch({ 73 | curl::handle_setopt( 74 | handle = handle, 75 | customrequest = customrequest) 76 | }, error = function(e){ 77 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 78 | }) 79 | 80 | return(c(handle = handle, customrequest = customrequest)) 81 | } 82 | -------------------------------------------------------------------------------- /R/define-searchrequest-string.R: -------------------------------------------------------------------------------- 1 | #' Define string search request 2 | #' @param expr A character string specifying the word or expression to search 3 | #' for in messages. 4 | #' @param where A mandatory character string specifying in which 5 | #' message's Section or Header Field to search for the provided string. For 6 | #' some available options, see \code{\link{section_or_field_options}}. 7 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 8 | #' CRITERIA". Default is \code{FALSE}. 9 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 10 | #' presented as message's sequence numbers. A message sequence number is a 11 | #' message's relative position to the oldest message in the mailbox. It may 12 | #' change after deleting or moving messages. If a message is deleted, sequence 13 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 14 | #' performed using the \code{"UID"} or unique identifier, and results are 15 | #' presented as such. UIDs are always the same during the life cycle of a message. 16 | #' @param flag Optional argument that sets one or more flags as an additional 17 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 18 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 19 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 20 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 21 | #' will condense the results: instead of writing down the whole sequences of messages' 22 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 23 | #' which decreases transmission costs. This argument can be used along with 24 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 25 | #' supports \code{ESEARCH} with 26 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 27 | #' @param handle A curl handle object. 28 | #' @noRd 29 | define_searchrequest_string <- function(expr, where, negate, use_uid, flag, 30 | esearch, handle) { 31 | 32 | # esearch 33 | if (isTRUE(esearch)) { 34 | esearch_string = "RETURN () " 35 | } else { 36 | esearch_string = NULL 37 | } 38 | 39 | # flag 40 | if (!is.null(flag)) { 41 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 42 | flag_string = paste0(flag_string, " ") 43 | } else { 44 | flag_string = NULL 45 | } 46 | 47 | # use_uid 48 | if (isTRUE(use_uid)) { 49 | use_uid_string = "UID " 50 | } else { 51 | use_uid_string = NULL 52 | } 53 | 54 | # negate 55 | if (isTRUE(negate)) { 56 | negate_string = "NOT " 57 | } else { 58 | negate_string = NULL 59 | } 60 | 61 | # section_or_field 62 | section_or_field_string = paste0(where, " ") 63 | 64 | # string 65 | expr_string = paste0('"', expr, '"') 66 | 67 | customrequest <- paste0(use_uid_string, "SEARCH ", esearch_string, flag_string, 68 | negate_string, "(", section_or_field_string, 69 | expr_string, ")") 70 | 71 | tryCatch({ 72 | curl::handle_setopt( 73 | handle = handle, 74 | customrequest = customrequest) 75 | }, error = function(e){ 76 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 77 | }) 78 | 79 | return(c(handle = handle, customrequest = customrequest)) 80 | } 81 | -------------------------------------------------------------------------------- /R/define-searchrequest-within.R: -------------------------------------------------------------------------------- 1 | #' Define within search request 2 | #' @param operation The type of within operation, \code{YOUNGER} or \code{OLDER}. 3 | #' @param seconds An integer specifying the number of seconds to be used as 4 | #' the search criterion. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param flag Optional argument that sets one or more flags as an additional 15 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 16 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 17 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 18 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 19 | #' will condense the results: instead of writing down the whole sequences of messages' 20 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 21 | #' which decreases transmission costs. This argument can be used along with 22 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 23 | #' supports \code{ESEARCH} with 24 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 25 | #' @param handle A curl handle object. 26 | #' @noRd 27 | define_searchrequest_within <- function(operation, seconds, negate, use_uid, flag, 28 | esearch, handle) { 29 | 30 | # esearch 31 | if (isTRUE(esearch)) { 32 | esearch_string = "RETURN () " 33 | } else { 34 | esearch_string = NULL 35 | } 36 | 37 | # flag 38 | if (!is.null(flag)) { 39 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 40 | flag_string = paste0(flag_string, " ") 41 | } else { 42 | flag_string = NULL 43 | } 44 | 45 | # use_uid 46 | if (isTRUE(use_uid)) { 47 | use_uid_string = "UID " 48 | } else { 49 | use_uid_string = NULL 50 | } 51 | 52 | # negate 53 | if (isTRUE(negate)) { 54 | negate_string = "NOT " 55 | } else { 56 | negate_string = NULL 57 | } 58 | 59 | customrequest <- paste0(use_uid_string, "SEARCH ", esearch_string, flag_string, 60 | negate_string, operation, ' ', seconds) 61 | 62 | tryCatch({ 63 | curl::handle_setopt( 64 | handle = handle, 65 | customrequest = customrequest) 66 | }, error = function(e){ 67 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 68 | }) 69 | 70 | return(c(handle = handle, customrequest = customrequest)) 71 | } 72 | -------------------------------------------------------------------------------- /R/delete-msg-int-new.R: -------------------------------------------------------------------------------- 1 | #' Delete AND expunge selected messages in the selected mail folder (INTERNAL HELPER) 2 | #' @param msg_uid A \code{numeric vector} containing one or more messages UIDs. 3 | #' Only UIDs are allowed in this operation (note the "u" in msg_\emph{u}id). 4 | #' @param use_uid Default is \code{FALSE}. In this case, the operation will 5 | #' be performed using message sequence numbers. A message sequence number 6 | #' is a message's relative position to the oldest message in a mail folder. 7 | #' It may change after deleting or moving messages. If a message is deleted, 8 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 9 | #' command will be performed using the \code{"UID"} or unique identifier. 10 | #' UIDs are always the same during the life cycle of a message in a mail folder. 11 | #' @param mute A \code{logical}. If \code{TRUE}, the function silently 12 | #' executes the command without providing a confirmation message. Default is 13 | #' \code{FALSE}. 14 | #' @param retries Number of attempts to connect and execute the command. 15 | #' Default is \code{1}. 16 | #' @noRd 17 | delete_msg_int <- function(self, msg_uid, use_uid, mute, retries = 1) { 18 | 19 | check_args(msg_uid = msg_uid, use_uid = use_uid, mute = mute, retries = retries) # we have to pass 20 | #.. the argg as arg = arg, so the check_args function can capture the names 21 | 22 | # forcing retries as an integer 23 | retries <- as.integer(retries) 24 | 25 | # self$imapconf$url <- utils::URLencode(gsub("/+$", "", self$url)) 26 | url <- self$con_params$url 27 | 28 | # isolating the handle 29 | h <- self$con_handle 30 | 31 | # prepare msg_id strings 32 | msg_string = paste0(msg_id, collapse = ",") 33 | 34 | # setting customrequest 35 | if (isTRUE(use_uid)) { 36 | 37 | customrequest <- paste0("UID STORE ", msg_string, " FLAGS (\\Deleted)") 38 | 39 | } else { 40 | 41 | customrequest <- paste0("STORE ", msg_string, " FLAGS (\\Deleted)") 42 | 43 | } 44 | 45 | execute_complementary_operations(self, url, handle = h, customrequest, retries) 46 | 47 | expunge(self = self, msg_uid = msg_uid, mute = TRUE, retries = 0) 48 | 49 | # handle sanitizing 50 | rm(h) 51 | 52 | # final_output <- list("imapconf" = imapconf, "msg_id" = msg_id) # 2nd arg bit different from others 53 | if (!mute) { 54 | if (self$con_params$verbose) { 55 | Sys.sleep(0.01) 56 | } 57 | cat(paste0('\n::mRpostman: message(s) marked as "\\Deleted"')) # v0.3.2 58 | # using the folder name without any transformation 59 | } 60 | # will allow users to pipe more operations after adding flags 61 | return(TRUE) #ou 62 | # invisible(msg_id) 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /R/delete-msg-int.R: -------------------------------------------------------------------------------- 1 | #' Delete message(s) in the selected mail folder (INTERNAL HELPER) 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param mute A \code{logical}. If \code{TRUE}, the function silently 12 | #' executes the command without providing a confirmation message. Default is 13 | #' \code{FALSE}. 14 | #' @param retries Number of attempts to connect and execute the command. 15 | #' Default is \code{1}. 16 | #' @noRd 17 | delete_msg_int <- function(self, msg_id, use_uid, mute, retries = 1) { 18 | 19 | check_args(msg_id = msg_id, use_uid = use_uid, mute = mute, retries = retries) # we have to pass 20 | #.. the argg as arg = arg, so the check_args function can capture the names 21 | 22 | # forcing retries as an integer 23 | retries <- as.integer(retries) 24 | 25 | # self$imapconf$url <- utils::URLencode(gsub("/+$", "", self$url)) 26 | url <- self$con_params$url 27 | 28 | # isolating the handle 29 | h <- self$con_handle 30 | 31 | # prepare msg_id strings 32 | msg_string = paste0(msg_id, collapse = ",") 33 | 34 | # setting customrequest 35 | if (isTRUE(use_uid)) { 36 | 37 | customrequest <- paste0("UID STORE ", msg_string, " FLAGS (\\Deleted)") 38 | 39 | } else { 40 | 41 | customrequest <- paste0("STORE ", msg_string, " FLAGS (\\Deleted)") 42 | 43 | } 44 | 45 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 46 | retries) 47 | 48 | # handle sanitizing 49 | rm(h) 50 | 51 | # final_output <- list("imapconf" = imapconf, "msg_id" = msg_id) # 2nd arg bit different from others 52 | if (!mute) { 53 | if (self$con_params$verbose) { 54 | Sys.sleep(0.01) 55 | } 56 | cat(paste0('\n::mRpostman: message(s) deleted.')) # v0.3.2 57 | # using the folder name without any transformation 58 | } 59 | # will allow users to pipe more operations after adding flags 60 | # return(TRUE) #ou 61 | return(msg_id) 62 | # invisible(msg_id) 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /R/esearch-count-int.R: -------------------------------------------------------------------------------- 1 | #' Count the number of messages with an specific flag(s) in a 2 | #' folder (depend on ESEARCH capability) (INTERNAL HELPER) 3 | #' @param flag Mandatory parameter that specifies one or more flags as a 4 | #' filter to the counting operation. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 5 | #' to list the flags in a selected mail folder. 6 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 7 | #' presented as message's sequence numbers. A message sequence number is a 8 | #' message's relative position to the oldest message in the mailbox. It may 9 | #' change after deleting or moving messages. If a message is deleted, 10 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 11 | #' command will be performed using the \code{"UID"} or unique identifier, 12 | #' and results are presented as such. UIDs are always the same during the 13 | #' life cycle of a message. 14 | #' @param retries Number of attempts to connect and execute the command. 15 | #' Default is \code{1}. 16 | #' @noRd 17 | esearch_count_int <- function(self, flag, use_uid = FALSE, retries = 1) { 18 | 19 | # checks 20 | check_args(flag = flag, use_uid = use_uid, retries = retries) 21 | 22 | # flag/name (especial) 23 | # if (!is.null(flag)) { 24 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 25 | flag_string = paste0(flag_string, "") # different here because flag is the main parameter of search 26 | # } else { 27 | # flag_string = NULL 28 | # } 29 | 30 | # forcing retries as an integer 31 | retries <- as.integer(retries) 32 | 33 | url <- self$con_params$url 34 | 35 | h <- self$con_handle 36 | 37 | # adding the SEARCH id RETURN COUNT customrequest 38 | if (isTRUE(use_uid)) { 39 | 40 | customrequest <- paste0("UID SEARCH RETURN (COUNT) ", flag_string) 41 | 42 | } else { 43 | 44 | customrequest <- paste0("SEARCH RETURN (COUNT) ", flag_string) 45 | 46 | } 47 | 48 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 49 | retries) 50 | 51 | 52 | response <- as.numeric(as.character( 53 | stringr::str_match_all( 54 | string = rawToChar(response$content), 55 | pattern = "COUNT ([\\d]+)\r\n")[[1]][,2])) 56 | 57 | names(response) <- c("COUNT") 58 | # handle sanitizing 59 | rm(h) 60 | return(response) 61 | 62 | } 63 | -------------------------------------------------------------------------------- /R/esearch-max-id-int.R: -------------------------------------------------------------------------------- 1 | #' Search the maximum message id in the selected mail folder 2 | #' (depend on ESEARCH capability) (INTERNAL HELPER) 3 | #' @param flag Mandatory parameter that specifies one or more flags as a 4 | #' filter to the searching operation. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 5 | #' to list the flags in a selected mail folder. 6 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 7 | #' presented as message's sequence numbers. A message sequence number is a 8 | #' message's relative position to the oldest message in the mailbox. It may 9 | #' change after deleting or moving messages. If a message is deleted, 10 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 11 | #' command will be performed using the \code{"UID"} or unique identifier, 12 | #' and results are presented as such. UIDs are always the same during the 13 | #' life cycle of a message. 14 | #' @param retries Number of attempts to connect and execute the command. 15 | #' Default is \code{1}. 16 | #' @noRd 17 | esearch_max_id_int <- function(self, flag, use_uid, retries) { 18 | 19 | # previous folder selection checking 20 | # if (!is.character(flag)) { 21 | # stop('"flag" argument must of type character.') 22 | # } 23 | assertthat::assert_that( 24 | is.character(flag), 25 | msg='"flag" argument must of type character.') 26 | 27 | check_args(use_uid = use_uid, retries = retries) 28 | 29 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 30 | flag_string = paste0(flag_string, "") # different here because flag is the main parameter of search 31 | 32 | retries <- as.integer(retries) 33 | 34 | url <- self$con_params$url 35 | 36 | # isolating the handle 37 | h <- self$con_handle 38 | 39 | # setting customrequest 40 | if (isTRUE(use_uid)) { 41 | 42 | customrequest <- paste0("UID SEARCH RETURN (MAX) ", flag_string) 43 | 44 | 45 | } else { 46 | 47 | customrequest <- paste0("SEARCH RETURN (MAX) ", flag_string) 48 | 49 | } 50 | 51 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 52 | retries) 53 | 54 | 55 | response <- as.numeric(as.character( 56 | stringr::str_match_all( 57 | string = rawToChar(response$content), 58 | pattern = "MAX ([\\d]+)\r\n")[[1]][,2])) 59 | 60 | names(response) <- c("MAX") 61 | 62 | # handle sanitizing 63 | rm(h) 64 | 65 | return(response) 66 | 67 | } 68 | -------------------------------------------------------------------------------- /R/esearch-min-id-int.R: -------------------------------------------------------------------------------- 1 | #' Search the minimum message id in the selected mail folder 2 | #' (depend on ESEARCH capability) (INTERNAL HELPER) 3 | #' @param flag Mandatory parameter that specifies one or more flags as a 4 | #' filter to the searching operation. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 5 | #' to list the flags in a selected mail folder. 6 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 7 | #' presented as message's sequence numbers. A message sequence number is a 8 | #' message's relative position to the oldest message in the mailbox. It may 9 | #' change after deleting or moving messages. If a message is deleted, 10 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 11 | #' command will be performed using the \code{"UID"} or unique identifier, 12 | #' and results are presented as such. UIDs are always the same during the 13 | #' life cycle of a message. 14 | #' @param retries Number of attempts to connect and execute the command. 15 | #' Default is \code{1}. 16 | #' @noRd 17 | esearch_min_id_int <- function(self, flag, use_uid, retries) { 18 | 19 | # if (!is.character(flag)) { 20 | # stop('"flag" argument must of type character.') 21 | # } 22 | assertthat::assert_that( 23 | is.character(flag), 24 | msg='"flag" argument must of type character.') 25 | 26 | check_args(use_uid = use_uid, retries = retries) 27 | 28 | flag_string <- paste(flag, collapse = " ") #v0.9.0 (for more than one flag passed) 29 | flag_string = paste0(flag_string, "") # different here because flag is the main parameter of search 30 | 31 | retries <- as.integer(retries) 32 | 33 | url <- self$con_params$url 34 | 35 | # isolating the handle 36 | h <- self$con_handle 37 | 38 | # setting customrequest 39 | if (isTRUE(use_uid)) { 40 | 41 | customrequest <- paste0("UID SEARCH RETURN (MIN) ", flag_string) 42 | 43 | 44 | } else { 45 | 46 | customrequest <- paste0("SEARCH RETURN (MIN) ", flag_string) 47 | 48 | } 49 | 50 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 51 | retries) 52 | 53 | 54 | response <- as.numeric(as.character( 55 | stringr::str_match_all( 56 | string = rawToChar(response$content), 57 | pattern = "MIN ([\\d]+)\r\n")[[1]][,2])) 58 | 59 | names(response) <- c("MIN") 60 | 61 | # handle sanitizing 62 | rm(h) 63 | 64 | return(response) 65 | 66 | } 67 | -------------------------------------------------------------------------------- /R/execute-complementary-operations.R: -------------------------------------------------------------------------------- 1 | #' Execution engine for all the complementary commands 2 | #' @param self The R6 connection object. 3 | #' @param url A string containing the url from the \code{IMAP_conn$imapconf} object. 4 | #' @param handle A curl handle object with the custom request already defined. 5 | #' @param customrequest A string containing the custom request to the server that will 6 | #' be added to the curl handle. 7 | #' @param retries Number of attempts to connect and execute the command. Default 8 | #' is \code{1}. 9 | #' @noRd 10 | execute_complementary_operations <- function(self, url, handle, customrequest, 11 | retries) { 12 | 13 | # previous folder selection checking 14 | # if (is.na(self$folder)) { 15 | # stop('No folder previously selected.') 16 | # } 17 | assertthat::assert_that( 18 | !is.na(self$con_params$folder), 19 | msg='No folder previously selected.') 20 | 21 | tryCatch({ 22 | curl::handle_setopt( 23 | handle = handle, 24 | customrequest = customrequest) 25 | }, error = function(e){ 26 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 27 | }) 28 | 29 | # REQUEST 30 | response <- tryCatch({ 31 | curl::curl_fetch_memory(url, handle = handle) 32 | }, error = function(e){ 33 | # print(e$message) 34 | response_error_handling(e$message[1]) # returns NULL for operation timeout: try reconnection 35 | }) 36 | 37 | if (is.null(response)) { 38 | 39 | # it is not necessary to select again 40 | count_retries = 0 #the first try was already counted 41 | # FORCE appending fresh_connect 42 | # curl::handle_setopt(handle = h, fresh_connect = TRUE) 43 | select_folder_int(self, name = self$con_params$folder, mute = TRUE, retries = 0) # ok! v0.0.9 44 | 45 | while (is.null(response) && count_retries < retries) { 46 | count_retries = count_retries + 1 47 | 48 | # reset customrequest in handle 49 | tryCatch({ 50 | curl::handle_setopt( 51 | handle = handle, 52 | customrequest = customrequest) 53 | }, error = function(e){ 54 | stop("The connection handle is dead. Please, configure a new IMAP connection with ImapCon$new().") 55 | }) 56 | 57 | # REQUEST 58 | response <- tryCatch({ 59 | curl::curl_fetch_memory(url, handle = handle) 60 | }, error = function(e){ 61 | # print(e$message) 62 | response_error_handling(e$message[1]) # returns NULL for operation timeout: try reconnection 63 | }) 64 | } 65 | 66 | if (is.null(response)) { 67 | stop('Request error: the server returned an error.') 68 | } 69 | 70 | } 71 | 72 | # handle sanitizing 73 | rm(handle) 74 | 75 | return(response) 76 | 77 | } 78 | -------------------------------------------------------------------------------- /R/expunge-int.R: -------------------------------------------------------------------------------- 1 | #' Expunge the selected mail folder or specific message(s) (by UID) (INTERNAL HELPER) 2 | #' @param msg_uid A \code{numeric vector} containing one or more messages UIDs. 3 | #' This operation does not allow sequence numbers. 4 | #' @param mute A \code{logical}. Provides a confirmation message if the 5 | #' command is successfully executed. Default is \code{FALSE}. 6 | #' @param retries Number of attempts to connect and execute the command. 7 | #' Default is \code{1}. 8 | #' @noRd 9 | expunge_int <- function(self, msg_uid, mute, retries) { 10 | 11 | # expunge only acepts UIDs if the user is to pass a specific message to expunge 12 | 13 | check_args(msg_uid = msg_uid, mute = mute, retries = retries) 14 | 15 | retries <- as.integer(retries) 16 | 17 | url <- self$con_params$url 18 | 19 | # isolating the handle 20 | h <- self$con_handle 21 | 22 | # prepare msg_id strings 23 | msg_string = paste0(msg_uid, collapse = ",") 24 | 25 | # setting customrequest 26 | if (!is.null(msg_uid)) { 27 | 28 | customrequest <- paste0("UID EXPUNGE ", msg_string) 29 | 30 | } else { 31 | 32 | customrequest <- "EXPUNGE" 33 | 34 | } 35 | 36 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 37 | retries) # special case here: use_uid = TRUE 38 | 39 | # handle sanitizing 40 | rm(h) 41 | 42 | # final_output <- list("imapconf" = imapconf, "msg_id" = msg_id) # 2nd arg bit different from others 43 | if (!mute) { 44 | if (self$con_params$verbose) { 45 | Sys.sleep(0.01) 46 | } 47 | cat(paste0("\n::mRpostman: expunge successfuly executed.")) # v0.3.2 48 | # using the folder name without any transformation 49 | } 50 | # will allow users to pipe more operations after adding flags 51 | return(TRUE) #ou 52 | # invisible(msg_id) 53 | 54 | } 55 | -------------------------------------------------------------------------------- /R/fetch-metadata-int.R: -------------------------------------------------------------------------------- 1 | #' Fetch message's metadata 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param attribute An optional \code{character vector} specifying one or more 12 | #' attributes of the metadata of a message to fetch. See \link{metadata_options}. 13 | #' @param peek If \code{TRUE}, it does not mark messages as "read" after 14 | #' fetching. Default is \code{TRUE}. 15 | #' @param partial \code{NULL} or a character string with format 16 | #' "startchar.endchar" indicating the size (in characters) of a message slice 17 | #' to fetch. Default is \code{NULL}, which will fetch the full specified content. 18 | #' @param write_to_disk If \code{TRUE}, writes the fetch content of each message 19 | #' to a text file in a local folder inside the working directory, also 20 | #' returning the results with \code{invisible()}. Default is \code{FALSE}. 21 | #' @param keep_in_mem If \code{TRUE}, keeps a copy of each fetch result while 22 | #' the operation is being performed with \code{write_to_disk = TRUE}. Default 23 | #' is \code{FALSE}, and it can only be set \code{TRUE} when 24 | #' \code{write_to_disk = TRUE}. 25 | #' @param mute A \code{logical}. It is only effective when \code{write_to_disk = TRUE} 26 | #' and \code{keep_in_mem = FALSE}. It Provides a confirmation message if the 27 | #' command is successfully executed. Default is \code{FALSE}. 28 | #' @param retries Number of attempts to connect and execute the command. Default 29 | #' is \code{1}. 30 | #' @noRd 31 | fetch_metadata_int <- function(self, msg_id, use_uid, attribute, write_to_disk, 32 | keep_in_mem, mute, retries) { 33 | 34 | #check 35 | check_args(msg_id = msg_id, use_uid = use_uid, attribute = attribute, 36 | write_to_disk = write_to_disk, keep_in_mem = keep_in_mem, 37 | mute = mute, retries = retries) 38 | 39 | if (is.null(attribute)) { 40 | attribute <- metadata_options() 41 | } 42 | 43 | attribute <- paste0(attribute, collapse = " ") 44 | 45 | # use_uid 46 | if (isTRUE(use_uid)) { 47 | use_uid_string = "UID " 48 | } else { 49 | use_uid_string = NULL 50 | } 51 | 52 | fetch_request <- paste0(use_uid_string, "FETCH ", "#", " (", attribute, ")") # "#" serves as a place holder for the msg's ids 53 | 54 | # loop exec 55 | fetch_type = "metadata" 56 | msg_list <- execute_fetch_loop(self = self, msg_id = msg_id, fetch_request = fetch_request, 57 | use_uid = use_uid, write_to_disk = write_to_disk, 58 | keep_in_mem = keep_in_mem, retries = retries, 59 | fetch_type = fetch_type, metadata_attribute = attribute) 60 | 61 | 62 | if (isFALSE(keep_in_mem)) { 63 | 64 | rm(msg_list) 65 | 66 | if (!mute) { 67 | cat(paste0("\n::mRpostman: fetch operation is complete.\n")) # v0.3.2 68 | # using the folder name without any transformation 69 | } 70 | 71 | return(TRUE) 72 | 73 | } else { 74 | return(msg_list) 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /R/fetch-text-int.R: -------------------------------------------------------------------------------- 1 | #' Fetch message text 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param peek If \code{TRUE}, it does not mark messages as "read" after 12 | #' fetching. Default is \code{TRUE}. 13 | #' @param partial \code{NULL} or a character string with format 14 | #' "startchar.endchar" indicating the size (in characters) of a message slice 15 | #' to fetch. Default is \code{NULL}, which will fetch the full specified content. 16 | #' @param write_to_disk If \code{TRUE}, writes the fetch content of each message 17 | #' to a text file in a local folder inside the working directory, also 18 | #' returning the results with \code{invisible()}. Default is \code{FALSE}. 19 | #' @param keep_in_mem If \code{TRUE}, keeps a copy of each fetch result while 20 | #' the operation is being performed with \code{write_to_disk = TRUE}. Default 21 | #' is \code{FALSE}, and it can only be set \code{TRUE} when 22 | #' \code{write_to_disk = TRUE}. 23 | #' @param mute A \code{logical}. It is only effective when \code{write_to_disk = TRUE} 24 | #' and \code{keep_in_mem = FALSE}. It Provides a confirmation message if the 25 | #' command is successfully executed. Default is \code{FALSE}. 26 | #' @param base64_decode If \code{TRUE}, tries to guess and decode the fetched 27 | #' text from base64 format to \code{character}. Default is \code{FALSE}. 28 | #' @param retries Number of attempts to connect and execute the command. Default 29 | #' is \code{1}. 30 | #' @noRd 31 | fetch_text_int <- function(self, msg_id, use_uid, peek, partial, write_to_disk, 32 | keep_in_mem, mute, base64_decode, retries) { 33 | 34 | #check 35 | check_args(msg_id = msg_id, use_uid = use_uid, peek = peek, partial = partial, 36 | write_to_disk = write_to_disk, keep_in_mem = keep_in_mem, mute = mute, 37 | base64_decode = base64_decode, retries = retries) 38 | 39 | # peek 40 | if (isTRUE(peek)) { 41 | body_string = " BODY.PEEK[TEXT]" 42 | } else { 43 | body_string = " BODY[TEXT]" 44 | } 45 | 46 | # partial 47 | if (!is.null(partial)) { 48 | partial_string = paste0("<", partial, ">") 49 | } else { 50 | partial_string = NULL 51 | } 52 | 53 | # use_uid 54 | if (isTRUE(use_uid)) { 55 | use_uid_string = "UID " 56 | } else { 57 | use_uid_string = NULL 58 | } 59 | 60 | fetch_request <- paste0(use_uid_string, "FETCH ", "#", body_string, partial_string) # "#" serves as a place holder for the msg's ids 61 | 62 | # loop exec 63 | fetch_type = "text" 64 | msg_list <- execute_fetch_loop(self = self, msg_id = msg_id, fetch_request = fetch_request, 65 | use_uid = use_uid, write_to_disk = write_to_disk, 66 | keep_in_mem = keep_in_mem, retries = retries, 67 | fetch_type = fetch_type, 68 | base64_decode = base64_decode) #difference to other fetch functions is the base64_decode arg 69 | 70 | if (isFALSE(keep_in_mem)) { 71 | 72 | rm(msg_list) 73 | 74 | if (!mute) { 75 | cat(paste0("\n::mRpostman: fetch operation is complete.\n")) # v0.3.2 76 | # using the folder name without any transformation 77 | } 78 | 79 | return(TRUE) 80 | 81 | } else { 82 | return(msg_list) 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /R/fix-search-stripping.R: -------------------------------------------------------------------------------- 1 | #' Fix stripped search results 2 | #' @param response An \code{integer vector} containing message's ids from 3 | #' the search. 4 | #' @noRd 5 | fix_search_stripping <- function(response) { 6 | 7 | # sort numbers from response 8 | # when it is different from the original vector, fix that number 9 | # according to the number of digits of the next number to the right 10 | 11 | # it does not seem to work anymore. Gmail seems to changed the response 12 | # MS Exchange also informs that there is a stripping, but is not possible 13 | # to retrieve this message in the curl's current version 14 | 15 | sorted_response = sort(response) 16 | 17 | if (any(which(response != sorted_response))) { 18 | 19 | stripped_idx <- which(response != sorted_response)[[1]] 20 | 21 | stripped_number <- response[stripped_idx] 22 | 23 | nchar_stripped_number <- nchar(stripped_number) 24 | 25 | nchar_next_number <- nchar(response[stripped_idx+1]) 26 | 27 | response[stripped_idx] <- substr( 28 | x = stripped_number, 29 | start = (nchar_stripped_number - nchar_next_number)+1, 30 | stop = nchar_stripped_number) 31 | 32 | } 33 | 34 | return(as.integer(as.character(response))) 35 | } 36 | -------------------------------------------------------------------------------- /R/flag.R: -------------------------------------------------------------------------------- 1 | #' Criterion constructor function to be combined in a custom search statement 2 | #' @param name A string containing one or more flags to search for. Use 3 | #' \href{#method-list_flags}{\code{ImapCon$list_flags()}} to list the flags 4 | #' in a selected mail folder. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @family custom search 8 | #' @examples 9 | #' \dontrun{ 10 | #' # select folder & search 11 | #' con$select_folder(name = "INBOX") 12 | #' # search for messages with Flag "UNSEEN" AND NOT Smaller Than 512KB. 13 | #' res <- con$search(request = AND(flag("UNSEEN"), 14 | #' smaller_than(size = 512000, negate = TRUE))) 15 | #' } 16 | #' @export 17 | #' 18 | flag <- function(name, negate = FALSE) { 19 | 20 | 21 | check_args(name, negate) 22 | 23 | # setting part of the search string 24 | 25 | # flag/name (especial) 26 | # if (!is.null(flag)) { 27 | flag_string <- paste(name, collapse = " ") #v0.9.0 (for more than one flag passed) 28 | flag_string = paste0(flag_string, "") # different here because flag is the main parameter of search 29 | # } else { 30 | # flag_string = NULL 31 | # } 32 | 33 | if (!isTRUE(negate)) { 34 | out = paste0('(', flag_string, ')') 35 | 36 | } else { 37 | out = paste0('(NOT (', flag_string, '))') 38 | 39 | } 40 | 41 | return(out) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /R/has-attachment.R: -------------------------------------------------------------------------------- 1 | #' Attachments check 2 | #' @param msg An object of type \code{character} containing the whole MIME 3 | #' message. 4 | #' @noRd 5 | has_attachment <- function(msg, call_from) { 6 | 7 | if (call_from == "list_attachments" | call_from == "get_attachments") { 8 | check <- grepl(pattern = "Content-Disposition: (attachment|inline)", 9 | x = msg, ignore.case = TRUE) 10 | return(check) 11 | 12 | } else { 13 | check1 <- grepl(pattern = "Content-Disposition: (attachment|inline)", 14 | x = msg) 15 | 16 | check2 <- grepl(pattern = "attachment|inline", 17 | x = msg, ignore.case = TRUE) 18 | return(any(check1, check2)) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /R/larger-than.R: -------------------------------------------------------------------------------- 1 | #' @inherit smaller_than 2 | #' @family custom search 3 | #' @examples 4 | #' \dontrun{ 5 | #' # select folder & search 6 | #' con$select_folder(name = "INBOX") 7 | #' # search for messages containing the string "XYZ@@k-state.edu" in the 8 | #' # "FROM" field OR those that are LARGER than 512KB. 9 | #' res <- con$search(request = OR(string(expr = "XYZ@@k-state.edu", 10 | #' where = "FROM"), 11 | #' larger_than(size = 512000))) 12 | #' } 13 | #' 14 | #' @export 15 | #' 16 | larger_than <- function(size, negate = FALSE) { 17 | 18 | check_args(size, negate) 19 | 20 | # setting part of the search string 21 | 22 | if (!isTRUE(negate)) { 23 | out = paste0('(LARGER ', size, ')') 24 | 25 | } else { 26 | out = paste0('(NOT (LARGER ', size, '))') 27 | 28 | } 29 | 30 | return(out) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /R/metadata-options.R: -------------------------------------------------------------------------------- 1 | #' @title Message Metadata Options 2 | #' 3 | #' @description List Metadata fields used in messages. 4 | #' 5 | #' @return A \code{vector} containing message metadata fields. 6 | #' 7 | #' @note This function lists message metadata used by 8 | #' IMAP servers, according to the RFC 2060 (Crispin, 1996). 9 | #' 10 | #' @references Crispin, M., "Internet Message Access Protocol - Version 4rev1", 11 | #' RFC 2060, \doi{10.17487/RFC2060}, December 1996, 12 | #' \url{https://www.rfc-editor.org/info/rfc2060}. 13 | #' 14 | #' @family options 15 | #' 16 | #' @examples 17 | #' \dontrun{ 18 | #' 19 | #' library(mRpostman) 20 | #' metadata_options() 21 | #' 22 | #' } 23 | #' @export 24 | #' 25 | metadata_options <- function() { 26 | 27 | metadata_opts <- c("INTERNALDATE", "UID", "ENVELOPE", "FLAGS", "RFC822.SIZE", 28 | "BODYSTRUCTURE") 29 | 30 | return(metadata_opts) 31 | } 32 | -------------------------------------------------------------------------------- /R/modify-con-handle.R: -------------------------------------------------------------------------------- 1 | #' Reset curl handle parameters for an existing IMAP connection 2 | #' @param ... Further curl parameters (see \code{curl::curl_options}) that 3 | #' can be used with the IMAP protocol. Only for advanced users. 4 | #' @noRd 5 | modify_con_handle <- function(self, ...) { 6 | 7 | # only receives curl parameters for the handle 8 | 9 | # checks: 10 | # if (!is.character(con_params$url)) { 11 | # stop('Argument "url" must be a string, e.g. "imaps://imap.servername.com".') 12 | # } 13 | 14 | argg_list <- list(...) 15 | 16 | # print(argg_list) 17 | 18 | if ("username" %in% names(argg_list)) { 19 | 20 | assertthat::assert_that( 21 | is.character(argg_list$username), 22 | msg='Argument "username" must be a string, e.g. "myusername@myserver.com".') 23 | } 24 | 25 | if ("use_ssl" %in% names(argg_list)) { 26 | 27 | assertthat::assert_that( 28 | is.logical(argg_list$use_ssl), 29 | msg='Argument "use_ssl" must be a logical.') 30 | } 31 | 32 | if ("verbose" %in% names(argg_list)) { 33 | 34 | assertthat::assert_that( 35 | is.logical(argg_list$verbose), 36 | msg='Argument "verbose" must be a logical.') 37 | } 38 | 39 | if ("buffersize" %in% names(argg_list)) { 40 | 41 | assertthat::assert_that(all( 42 | is.numeric(argg_list$buffersize), 43 | argg_list$buffersize >= 16000 44 | ), 45 | msg='Argument "buffersize" must be an integer equal or greater than 16000, the minimum value for the libcurl buffer.') 46 | } 47 | 48 | if ("timeout_ms" %in% names(argg_list)) { 49 | 50 | assertthat::assert_that( 51 | is.numeric(argg_list$timeout_ms), 52 | msg='Argument "timeout_ms" must be a number indicating the time in milliseconds.') 53 | } 54 | 55 | if ("password" %in% names(argg_list)) { 56 | # na reset da password, automaticamente seta xoauth2_bearer <- NULL e vice versa 57 | assertthat::assert_that( 58 | is.character(argg_list$password), 59 | msg='Argument "password" must be a string, e.g. "my_pass".') 60 | 61 | argg_list$xoauth2_bearer <- NULL 62 | } 63 | 64 | if ("xoauth2_bearer" %in% names(argg_list)) { 65 | # passar todos osparametros para self$con_params$..., para nao ficarem perdidos no meio do self$ 66 | # fazer um teste para nao atribuir password nem xoauth2_bearer 67 | # na reset da password, automaticamente seta xoauth2_bearer <- NULL se existir e vice versa e passa para essa função (ver se vai funcionar) 68 | assertthat::assert_that( 69 | is.character(argg_list$xoauth2_bearer), 70 | msg='Argument "xoauth2_bearer" must be a string, e.g. "ya29.a0AXX...".') 71 | 72 | argg_list$password <- NULL 73 | } 74 | 75 | # config handle 76 | # id_to_drop <- c() 77 | # for (i in 1:length(argg_list)) { # as a precaution 78 | # 79 | # if (is.null(argg_list[[i]]) || names(argg_list)[i] == "url" || 80 | # names(argg_list)[i] == "folder" || names(argg_list)[i] == "self") { 81 | # id_to_drop <- append(id_to_drop, i) 82 | # } 83 | # } 84 | 85 | # print(argg_list) 86 | do.call(curl::handle_setopt, c(self$con_handle, argg_list)) # actually, argg_list will contain only one parameter 87 | 88 | invisible(TRUE) 89 | } 90 | -------------------------------------------------------------------------------- /R/move-msg-int.R: -------------------------------------------------------------------------------- 1 | #' Move message(s) between the selected folder and another one (INTERNAL HELPER) 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param to_folder A \code{character} string specifying the folder to which 12 | #' the messages will be copied. 13 | #' @param reselect A logical. If \code{TRUE}, calls 14 | #' \href{#method-select_folder}{\code{ImapCon$select_folder(name = to_folder)}} 15 | #' under the hood before returning the output. Default is \code{TRUE}. 16 | #' @param mute A \code{logical}. If \code{TRUE}, the function silently 17 | #' executes the command without providing a confirmation message. Default is 18 | #' \code{FALSE}. 19 | #' @param retries Number of attempts to connect and execute the command. 20 | #' Default is \code{1}. 21 | #' @noRd 22 | move_msg_int <- function(self, msg_id, use_uid, to_folder, reselect, mute, retries) { 23 | 24 | check_args(msg_id = msg_id, use_uid = use_uid, to_folder = to_folder, 25 | reselect = reselect, mute = mute, retries = retries) 26 | 27 | # forcing retries as an integer 28 | retries <- as.integer(retries) 29 | 30 | # quoting to guarantee folder with more than one name 31 | folder <- adjust_folder_name(self$con_params$folder) # there is a reselection in the end 32 | to_folder2 <- adjust_folder_name(to_folder) 33 | 34 | # forcing retries as an integer 35 | retries <- as.integer(retries) 36 | 37 | url <- self$con_params$url 38 | 39 | h <- self$con_handle 40 | 41 | # prepare msg_id strings 42 | msg_string = paste0(msg_id, collapse = ",") 43 | 44 | # customrequest parameter 45 | if (isTRUE(use_uid)) { 46 | 47 | customrequest <- paste0("UID MOVE ", msg_string, " ", to_folder2) 48 | 49 | } else { 50 | 51 | customrequest <- paste0("MOVE ", msg_string, " ", to_folder2) 52 | 53 | } 54 | 55 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 56 | retries) 57 | 58 | 59 | # reselecting 60 | if (isTRUE(reselect)) { 61 | # imapconf$folder = folder 62 | # select_folder(name = to_folder) 63 | reselected_folder <- select_folder_int(self, name = to_folder, mute = mute, retries = 0) # ok! v0.0.9 64 | } else { 65 | reselected_folder <- NULL 66 | } 67 | 68 | if (!mute) { 69 | if (self$con_params$verbose) { 70 | Sys.sleep(0.01) 71 | } 72 | cat(paste0("\n::mRpostman: message(s) moved")) # v0.3.2 73 | # using the folder name without any transformation 74 | } 75 | 76 | # final_output <- list("imapconf" = imapconf, "msg_id" = msg_id) # 2nd arg bit different from others 77 | # will allow users to pipe more operations after adding flags 78 | return(list(msg_id = msg_id, folder = reselected_folder)) 79 | 80 | } 81 | -------------------------------------------------------------------------------- /R/older-than.R: -------------------------------------------------------------------------------- 1 | #' Criterion constructor function to be combined in a custom search statement 2 | #' @param seconds An integer specifying the number of seconds to be used as 3 | #' the search criterion. 4 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 5 | #' CRITERIA". Default is \code{FALSE}. 6 | #' @note To be able to use this functionality, the server must support the 7 | #' \code{WITHIN} capability. 8 | #' @family custom search 9 | #' @examples 10 | #' \dontrun{ 11 | #' # select folder & search 12 | #' con$select_folder(name = "INBOX") 13 | #' # search for messages containing the string "XYZ@@k-state.edu" in the 14 | #' # "FROM" field AND those that are OLDER than 3600 seconds (1 hour). 15 | #' res <- con$search(request = AND(string(expr = "XYZ@@k-state.edu", 16 | #' where = "FROM"), 17 | #' older_than(seconds = 3600))) 18 | #' } 19 | #' 20 | #' @export 21 | #' 22 | older_than <- function(seconds, negate = FALSE) { 23 | 24 | check_args(seconds, negate) 25 | 26 | # setting part of the search string 27 | 28 | if (!isTRUE(negate)) { 29 | out = paste0('(OLDER ', seconds, ')') 30 | 31 | } else { 32 | out = paste0('(NOT (OLDER ', seconds, '))') 33 | 34 | } 35 | 36 | return(out) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /R/on.R: -------------------------------------------------------------------------------- 1 | #' @inherit before 2 | #' @family custom search 3 | #' @examples 4 | #' \dontrun{ 5 | #' # select folder & search 6 | #' con$select_folder(name = "INBOX") 7 | #' # search for messages SINCE "17-Apr-2019" AND SMALLER than 512KB. 8 | #' res <- con$search(request = OR(on(date_char = "30-Jun-2019"), 9 | #' on(date_char = "22-Mar-2018"))) 10 | #' # search for messages received ON "30-Jun-2019" OR ON "22-Mar-2018". 11 | #' 12 | #' } 13 | #' @export 14 | #' 15 | on <- function(date_char, negate = FALSE) { 16 | 17 | 18 | check_args(date_char, negate) 19 | 20 | # setting part of the search string 21 | 22 | if (!isTRUE(negate)) { 23 | out = paste0('(ON ', date_char, ')') 24 | 25 | } else { 26 | out = paste0('(NOT (ON ', date_char, '))') 27 | 28 | } 29 | 30 | return(out) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /R/pipe.R: -------------------------------------------------------------------------------- 1 | #' Common Pipe operator 2 | #' 3 | #' @name %>% 4 | #' @rdname pipe 5 | #' @keywords internal 6 | #' @export 7 | #' @importFrom magrittr %>% 8 | NULL 9 | -------------------------------------------------------------------------------- /R/remove-flags-int.R: -------------------------------------------------------------------------------- 1 | #' Remove flag(s) of one or more messages 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param flags_to_unset A \code{character vector} containing one ore more 12 | #' flag names that will be unset (removed). If the flag to be removed is an 13 | #' system flag, such as \code{\\SEEN}, \code{\\ANSWERED}, the name should be 14 | #' preceded by two backslashes \code{\\}. 15 | #' @param mute A \code{logical}. Provides a confirmation message if the 16 | #' command is successfully executed. Default is \code{FALSE}. 17 | #' @param retries Number of attempts to connect and execute the command. 18 | #' Default is \code{1}. 19 | #' @noRd 20 | remove_flags_int <- function(self, msg_id, use_uid, flags_to_unset, mute, retries) { 21 | 22 | check_args(msg_id = msg_id, use_uid, flags_to_unset = flags_to_unset, 23 | mute = mute, 24 | retries = retries) 25 | 26 | retries <- as.integer(retries) 27 | 28 | url <- self$con_params$url 29 | 30 | # isolating the handle 31 | h <- self$con_handle 32 | 33 | # prepare flag and msg_id strings 34 | flags_string <- paste(flags_to_unset, collapse = " ") 35 | 36 | msg_string = paste0(msg_id, collapse = ",") 37 | 38 | 39 | # setting customrequest 40 | if (isTRUE(use_uid)) { 41 | 42 | customrequest <- paste0("UID STORE ", msg_string, " -FLAGS ", "(", flags_string, ")") 43 | 44 | 45 | } else { 46 | 47 | customrequest <- paste0("STORE ", msg_string, " -FLAGS ", "(", flags_string, ")") 48 | 49 | } 50 | 51 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 52 | retries) 53 | 54 | # capture possible errors (in case of non-existent/allowed flags, curl does not assess the server response as an error) 55 | if (!is.null(response)) { 56 | error_check <- grepl(pattern = "^\\* NO ", x = rawToChar(response$headers)) # it will be on headers in this case 57 | if (isTRUE(error_check)) { 58 | stop(unlist(regmatches(rawToChar(response$headers), 59 | regexec("\\* NO (.*?)\r\n", 60 | rawToChar(response$headers))))[[2]]) 61 | } # if a flag "\flag" does not exist, it returns NULL (a regular error that we are used to) 62 | } 63 | 64 | if (!mute) { 65 | if (self$con_params$verbose) { 66 | Sys.sleep(0.01) 67 | } 68 | cat(paste0("\n::mRpostman: flag(s) successfuly removed.")) # v0.3.2 69 | # using the folder name without any transformation 70 | } 71 | 72 | # handle sanitizing 73 | rm(h) 74 | 75 | # return(TRUE) 76 | return(msg_id) 77 | 78 | } 79 | -------------------------------------------------------------------------------- /R/replace-flags-int.R: -------------------------------------------------------------------------------- 1 | #' Replace the current flags of one or more messages 2 | #' @param msg_id A \code{numeric vector} containing one or more message ids. 3 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 4 | #' presented as message's sequence numbers. A message sequence number is a 5 | #' message's relative position to the oldest message in the mailbox. It may 6 | #' change after deleting or moving messages. If a message is deleted, 7 | #' sequence numbers are reordered to fill the gap. If \code{TRUE}, the 8 | #' command will be performed using the \code{"UID"} or unique identifier, 9 | #' and results are presented as such. UIDs are always the same during the 10 | #' life cycle of a message. 11 | #' @param flags_to_set A \code{character vector} containing one ore more flag 12 | #' names that will replace the current ones. If the flag to be set is an 13 | #' system flag, such as \code{\\SEEN}, \code{\\ANSWERED}, the name should be 14 | #' preceded by two backslashes \code{\\}. 15 | #' @param mute A \code{logical}. Provides a confirmation message if the 16 | #' command is successfully executed. Default is \code{FALSE}. 17 | #' @param retries Number of attempts to connect and execute the command. 18 | #' Default is \code{1}. 19 | #' @noRd 20 | replace_flags_int <- function(self, msg_id, use_uid, flags_to_set, mute, retries) { 21 | 22 | check_args(msg_id = msg_id, use_uid, flags_to_set = flags_to_set, 23 | mute = mute, 24 | retries = retries) 25 | 26 | retries <- as.integer(retries) 27 | 28 | url <- self$con_params$url 29 | 30 | # isolating the handle 31 | h <- self$con_handle 32 | 33 | # prepare flag and msg_id strings 34 | flags_string <- paste(flags_to_set, collapse = " ") 35 | 36 | msg_string = paste0(msg_id, collapse = ",") 37 | 38 | # setting customrequest 39 | if (isTRUE(use_uid)) { 40 | 41 | customrequest <- paste0("UID STORE ", msg_string, " FLAGS ", "(", flags_string, ")") 42 | 43 | 44 | } else { 45 | 46 | customrequest <- paste0("STORE ", msg_string, " FLAGS ", "(", flags_string, ")") 47 | 48 | } 49 | 50 | response <- execute_complementary_operations(self, url, handle = h, customrequest, 51 | retries) 52 | 53 | # capture possible errors (in case of non-existent/allowed flags, curl does not assess the server response as an error) 54 | if (!is.null(response)) { 55 | error_check <- grepl(pattern = "^\\* NO ", x = rawToChar(response$headers)) # it will be on headers in this case 56 | if (isTRUE(error_check)) { 57 | stop(unlist(regmatches(rawToChar(response$headers), 58 | regexec("\\* NO (.*?)\r\n", 59 | rawToChar(response$headers))))[[2]]) 60 | } # if a flag "\flag" does not exist, it returns NULL (a regular error that we are used to) 61 | } 62 | 63 | if (!mute) { 64 | if (self$con_params$verbose) { 65 | Sys.sleep(0.01) 66 | } 67 | cat(paste0("\n::mRpostman: flag(s) successfuly replaced.")) # v0.3.2 68 | # using the folder name without any transformation 69 | } 70 | # handle sanitizing 71 | rm(h) 72 | 73 | # return(TRUE) 74 | return(msg_id) 75 | 76 | } 77 | -------------------------------------------------------------------------------- /R/response-error-handling.R: -------------------------------------------------------------------------------- 1 | #' Response error handling 2 | #' @param error_message A \code{character vector} containing the error message 3 | #' of the curl request. 4 | #' @noRd 5 | response_error_handling <- function(error_message) { 6 | 7 | pattern_resolving = 'Timeout was reached: Resolving timed out' 8 | 9 | pattern_login = 'Login denied' 10 | 11 | error_check_resolving <- grepl(pattern = pattern_resolving, x = error_message) 12 | 13 | error_check_login <- grepl(pattern = pattern_login, x = error_message) 14 | 15 | if (error_check_resolving) { 16 | 17 | stop("Resolving timeout: check your internet connection status or try to increase 18 | the timeout_ms argument in ImapCon$new().") 19 | 20 | } else if (error_check_login) { 21 | 22 | stop("Login denied: the server returned an authentication error.") 23 | 24 | } else { 25 | 26 | return(NULL) # for operation timeout: try reconnection 27 | 28 | } 29 | 30 | # schema: 31 | # 1) "Login denied" -- finish all atempts rigth away 32 | # 2) "Timeout was reached: Resolving timed out... internet connection error -- Finish all attempts right away 33 | # 3) "Timeout was reached: Operation timed out..." -- return NULL to do a retry 34 | 35 | } 36 | 37 | -------------------------------------------------------------------------------- /R/search-before-int.R: -------------------------------------------------------------------------------- 1 | #' Search by internal date (BEFORE) (INTERNAL HELPER) 2 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param flag Optional argument that sets one or more flags as an additional 15 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 16 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 17 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 18 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 19 | #' will condense the results: instead of writing down the whole sequences of messages' 20 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 21 | #' which decreases transmission costs. This argument can be used along with 22 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 23 | #' supports \code{ESEARCH} with 24 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 25 | #' @param retries Number of attempts to connect and execute the command. 26 | #' Default is \code{1}. 27 | #' @noRd 28 | search_before_int <- function(self, date_char, negate, use_uid, flag, esearch, 29 | retries) { 30 | 31 | check_args(date_char = date_char, negate = negate, use_uid = use_uid, flag = flag, 32 | esearch = esearch, retries = retries) 33 | 34 | # forcing retries as an integer 35 | retries <- as.integer(retries) 36 | 37 | url <- self$con_params$url 38 | 39 | # isolating the handle 40 | h <- self$con_handle 41 | 42 | #define customrequest 43 | define_out <- define_searchrequest_date(operation = "BEFORE", 44 | date_char = date_char, negate = negate, 45 | use_uid = use_uid, flag = flag, 46 | esearch = esearch, handle = h) 47 | 48 | h <- define_out$handle 49 | customrequest <- define_out$customrequest 50 | 51 | response <- execute_search(self = self, url = url, handle = h, 52 | customrequest = customrequest, esearch, retries) 53 | 54 | return(response) 55 | 56 | } 57 | -------------------------------------------------------------------------------- /R/search-flag-int.R: -------------------------------------------------------------------------------- 1 | #' Search by flag(s) (INTERNAL HELPER) 2 | #' @param name A string containing one or more flags to search for. Use 3 | #' \href{#method-list_flags}{\code{ImapCon$list_flags()}} to list the flags 4 | #' in a selected mail folder. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 15 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 16 | #' will condense the results: instead of writing down the whole sequences of messages' 17 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 18 | #' which decreases transmission costs. This argument can be used along with 19 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 20 | #' supports \code{ESEARCH} with 21 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 22 | #' @param retries Number of attempts to connect and execute the command. 23 | #' Default is \code{1}. 24 | #' @noRd 25 | search_flag_int <- function(self, name, negate, use_uid, esearch, retries) { 26 | 27 | check_args(name = name, negate = negate, use_uid = use_uid, esearch = esearch, 28 | retries = retries) 29 | 30 | # forcing retries as an integer 31 | retries <- as.integer(retries) 32 | 33 | url <- self$con_params$url 34 | 35 | # isolating the handle 36 | h <- self$con_handle 37 | 38 | #define customrequest 39 | define_out <- define_searchrequest_flag(name = name, negate = negate, 40 | use_uid = use_uid, esearch = esearch, 41 | handle = h) 42 | 43 | h <- define_out$handle 44 | customrequest <- define_out$customrequest 45 | 46 | response <- execute_search(self = self, url = url, handle = h, 47 | customrequest = customrequest, esearch, retries) 48 | 49 | return(response) 50 | 51 | } 52 | -------------------------------------------------------------------------------- /R/search-int.R: -------------------------------------------------------------------------------- 1 | #' Execute a custom search (INTERNAL HELPER) 2 | #' @param request A string directly specifying what to search or 3 | #' constructed by a combination of operators helper functions \code{\link{OR}} 4 | #' and \code{\link{AND}}, and criteria helper functions such as 5 | #' \code{\link{before}}, \code{\link{since}}, \code{\link{on}}, 6 | #' \code{\link{sent_before}}, \code{\link{sent_since}}, \code{\link{sent_on}}, 7 | #' \code{\link{flag}}, \code{\link{string}}, \code{\link{smaller_than}}, 8 | #' \code{\link{larger_than}}, \code{\link{younger_than}}, or 9 | #' \code{\link{younger_than}}. 10 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 11 | #' CRITERIA". Default is \code{FALSE}. 12 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 13 | #' presented as message's sequence numbers. A message sequence number is a 14 | #' message's relative position to the oldest message in the mailbox. It may 15 | #' change after deleting or moving messages. If a message is deleted, sequence 16 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 17 | #' performed using the \code{"UID"} or unique identifier, and results are 18 | #' presented as such. UIDs are always the same during the life cycle of a message. 19 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 20 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 21 | #' will condense the results: instead of writing down the whole sequences of messages' 22 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 23 | #' which decreases transmission costs. This argument can be used along with 24 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 25 | #' supports \code{ESEARCH} with 26 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 27 | #' @param retries Number of attempts to connect and execute the command. 28 | #' Default is \code{1}. 29 | #' @noRd 30 | search_int <- function(self, request, negate, use_uid, esearch, retries) { 31 | 32 | check_args(negate = negate, use_uid = use_uid, esearch = esearch, retries = retries) 33 | # we have to pass 34 | #.. the argg as arg = arg, in order to the check_argg capture the names 35 | 36 | # forcing retries as an integer 37 | retries <- as.integer(retries) 38 | 39 | url <- self$con_params$url 40 | 41 | # isolating the handle 42 | h <- self$con_handle 43 | 44 | #define customrequest to this handle 45 | define_out <- define_searchrequest_custom(request, negate = negate, 46 | use_uid = use_uid, 47 | esearch = esearch, handle = h) 48 | 49 | h <- define_out$handle 50 | customrequest <- define_out$customrequest 51 | 52 | response <- execute_search(self = self, url = url, handle = h, 53 | customrequest = customrequest, esearch, retries) 54 | 55 | return(response) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /R/search-larger-than-int.R: -------------------------------------------------------------------------------- 1 | #' Search by size (LARGER) (INTERNAL HELPER) 2 | #' @param size An integer specifying the size in bytes to be used as 3 | #' search criterion. 4 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 5 | #' CRITERIA". Default is \code{FALSE}. 6 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 7 | #' presented as message's sequence numbers. A message sequence number is a 8 | #' message's relative position to the oldest message in the mailbox. It may 9 | #' change after deleting or moving messages. If a message is deleted, sequence 10 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 11 | #' performed using the \code{"UID"} or unique identifier, and results are 12 | #' presented as such. UIDs are always the same during the life cycle of a message. 13 | #' @param flag Optional argument that sets one or more flags as an additional 14 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 15 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 16 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 17 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 18 | #' will condense the results: instead of writing down the whole sequences of messages' 19 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 20 | #' which decreases transmission costs. This argument can be used along with 21 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 22 | #' supports \code{ESEARCH} with 23 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 24 | #' @param retries Number of attempts to connect and execute the command. 25 | #' Default is \code{1}. 26 | #' @noRd 27 | search_larger_than_int <- function(self, size, negate, use_uid, flag, esearch, 28 | retries) { 29 | 30 | check_args(size = size, negate = negate, use_uid = use_uid, flag = flag, 31 | esearch = esearch, retries = retries) 32 | 33 | # forcing retries as an integer 34 | retries <- as.integer(retries) 35 | 36 | url <- self$con_params$url 37 | 38 | # isolating the handle 39 | h <- self$con_handle 40 | 41 | #define customrequest 42 | define_out <- define_searchrequest_size(operation = "LARGER", 43 | size = size, negate = negate, 44 | use_uid = use_uid, flag = flag, 45 | esearch = esearch, handle = h) 46 | 47 | h <- define_out$handle 48 | customrequest <- define_out$customrequest 49 | 50 | response <- execute_search(self = self, url = url, handle = h, 51 | customrequest = customrequest, esearch, retries) 52 | 53 | return(response) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /R/search-older-than-int.R: -------------------------------------------------------------------------------- 1 | #' Search WITHIN a time period (OLDER) (INTERNAL HELPER) 2 | #' @param seconds An integer specifying the number of seconds to be used as 3 | #' the search criterion. 4 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 5 | #' CRITERIA". Default is \code{FALSE}. 6 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 7 | #' presented as message's sequence numbers. A message sequence number is a 8 | #' message's relative position to the oldest message in the mailbox. It may 9 | #' change after deleting or moving messages. If a message is deleted, sequence 10 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 11 | #' performed using the \code{"UID"} or unique identifier, and results are 12 | #' presented as such. UIDs are always the same during the life cycle of a message. 13 | #' @param flag Optional argument that sets one or more flags as an additional 14 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 15 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 16 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 17 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 18 | #' will condense the results: instead of writing down the whole sequences of messages' 19 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 20 | #' which decreases transmission costs. This argument can be used along with 21 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 22 | #' supports \code{ESEARCH} with 23 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 24 | #' @param retries Number of attempts to connect and execute the command. 25 | #' Default is \code{1}. 26 | #' @noRd 27 | search_older_than_int <- function(self, seconds, negate, use_uid, flag, esearch, 28 | retries) { 29 | 30 | check_args(seconds = seconds, negate = negate, use_uid = use_uid, flag = flag, 31 | esearch = esearch, retries = retries) 32 | 33 | # forcing retries as an integer 34 | retries <- as.integer(retries) 35 | 36 | url <- self$con_params$url 37 | 38 | # isolating the handle 39 | h <- self$con_handle 40 | 41 | #define customrequest 42 | define_out <- define_searchrequest_within(operation = "OLDER", 43 | seconds = seconds, negate = negate, 44 | use_uid = use_uid, flag = flag, esearch = esearch, 45 | handle = h) 46 | 47 | h <- define_out$handle 48 | customrequest <- define_out$customrequest 49 | 50 | response <- execute_search(self = self, url = url, handle = h, 51 | customrequest = customrequest, esearch, retries) 52 | 53 | return(response) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /R/search-on-int.R: -------------------------------------------------------------------------------- 1 | #' Search by internal date (ON) (INTERNAL HELPER) 2 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param flag Optional argument that sets one or more flags as an additional 15 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 16 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 17 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 18 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 19 | #' will condense the results: instead of writing down the whole sequences of messages' 20 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 21 | #' which decreases transmission costs. This argument can be used along with 22 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 23 | #' supports \code{ESEARCH} with 24 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 25 | #' @param retries Number of attempts to connect and execute the command. 26 | #' Default is \code{1}. 27 | #' @noRd 28 | search_on_int <- function(self, date_char, negate, use_uid, flag, esearch, retries){ 29 | 30 | check_args(date_char = date_char, negate = negate, use_uid = use_uid, flag = flag, 31 | esearch = esearch, retries = retries) 32 | 33 | # forcing retries as an integer 34 | retries <- as.integer(retries) 35 | 36 | url <- self$con_params$url 37 | 38 | # isolating the handle 39 | h <- self$con_handle 40 | 41 | #define customrequest 42 | define_out <- define_searchrequest_date(operation = "ON", 43 | date_char = date_char, negate = negate, 44 | use_uid = use_uid, flag = flag, 45 | esearch = esearch, handle = h) 46 | 47 | h <- define_out$handle 48 | customrequest <- define_out$customrequest 49 | 50 | response <- execute_search(self = self, url = url, handle = h, 51 | customrequest = customrequest, esearch, retries) 52 | 53 | return(response) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /R/search-period-int.R: -------------------------------------------------------------------------------- 1 | #' Search by internal date (Period) 2 | #' @param since_date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param before_date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 6 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 7 | #' objects, since IMAP servers use this unusual date format. 8 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 9 | #' CRITERIA". Default is \code{FALSE}. 10 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 11 | #' presented as message's sequence numbers. A message sequence number is a 12 | #' message's relative position to the oldest message in the mailbox. It may 13 | #' change after deleting or moving messages. If a message is deleted, sequence 14 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 15 | #' performed using the \code{"UID"} or unique identifier, and results are 16 | #' presented as such. UIDs are always the same during the life cycle of a message. 17 | #' @param flag Optional argument that sets one or more flags as an additional 18 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 19 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 20 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 21 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 22 | #' will condense the results: instead of writing down the whole sequences of messages' 23 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 24 | #' which decreases transmission costs. This argument can be used along with 25 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 26 | #' supports \code{ESEARCH} with 27 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 28 | #' @param retries Number of attempts to connect and execute the command. 29 | #' Default is \code{1}. 30 | #' @noRd 31 | search_period_int <- function(self, since_date_char, before_date_char, negate, 32 | use_uid, flag, esearch, retries) { 33 | 34 | check_args(since_date_char = since_date_char, before_date_char = before_date_char, 35 | negate = negate, use_uid = use_uid, flag = flag, esearch = esearch, 36 | retries = retries) 37 | 38 | # forcing retries as an integer 39 | retries <- as.integer(retries) 40 | 41 | url <- self$con_params$url 42 | 43 | # isolating the handle 44 | h <- self$con_handle 45 | 46 | #define customrequest 47 | define_out <- define_searchrequest_period(operation1 = "SINCE", 48 | since_date_char = since_date_char, 49 | operation2 = "BEFORE", 50 | before_date_char = before_date_char, 51 | negate = negate, 52 | use_uid = use_uid, flag = flag, 53 | esearch = esearch, handle = h) 54 | 55 | h <- define_out$handle 56 | customrequest <- define_out$customrequest 57 | 58 | response <- execute_search(self = self, url = url, handle = h, 59 | customrequest = customrequest, esearch, retries) 60 | 61 | return(response) 62 | 63 | } 64 | -------------------------------------------------------------------------------- /R/search-sent-before-int.R: -------------------------------------------------------------------------------- 1 | #' Search by origination date (RFC-2822 Header - SENT BEFORE) 2 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param flag Optional argument that sets one or more flags as an additional 15 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 16 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 17 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 18 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 19 | #' will condense the results: instead of writing down the whole sequences of messages' 20 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 21 | #' which decreases transmission costs. This argument can be used along with 22 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 23 | #' supports \code{ESEARCH} with 24 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 25 | #' @param retries Number of attempts to connect and execute the command. 26 | #' Default is \code{1}. 27 | #' @noRd 28 | search_sent_before_int <- function(self, date_char, negate, use_uid, flag, esearch, 29 | retries) { 30 | 31 | check_args(date_char = date_char, negate = negate, use_uid = use_uid, flag = flag, 32 | esearch = esearch, retries = retries) 33 | 34 | # forcing retries as an integer 35 | retries <- as.integer(retries) 36 | 37 | url <- self$con_params$url 38 | 39 | # isolating the handle 40 | h <- self$con_handle 41 | 42 | #define customrequest 43 | define_out <- define_searchrequest_date(operation = "SENTBEFORE", 44 | date_char = date_char, negate = negate, 45 | use_uid = use_uid, flag = flag, esearch = esearch, 46 | handle = h) 47 | 48 | h <- define_out$handle 49 | customrequest <- define_out$customrequest 50 | 51 | response <- execute_search(self = self, url = url, handle = h, 52 | customrequest = customrequest, esearch, retries) 53 | 54 | return(response) 55 | 56 | } 57 | -------------------------------------------------------------------------------- /R/search-sent-on-int.R: -------------------------------------------------------------------------------- 1 | #' Search by origination date (RFC-2822 Header - SENT ON) 2 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param flag Optional argument that sets one or more flags as an additional 15 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 16 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 17 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 18 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 19 | #' will condense the results: instead of writing down the whole sequences of messages' 20 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 21 | #' which decreases transmission costs. This argument can be used along with 22 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 23 | #' supports \code{ESEARCH} with 24 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 25 | #' @param retries Number of attempts to connect and execute the command. 26 | #' Default is \code{1}. 27 | #' @noRd 28 | search_sent_on_int <- function(self, date_char, negate, use_uid, flag, esearch, retries) { 29 | 30 | check_args(date_char = date_char, negate = negate, use_uid = use_uid, flag = flag, 31 | esearch = esearch, retries = retries) 32 | 33 | # forcing retries as an integer 34 | retries <- as.integer(retries) 35 | 36 | url <- self$con_params$url 37 | 38 | # isolating the handle 39 | h <- self$con_handle 40 | 41 | #define customrequest 42 | define_out <- define_searchrequest_date(operation = "SENTON", 43 | date_char = date_char, negate = negate, 44 | use_uid = use_uid, flag = flag, 45 | esearch = esearch, handle = h) 46 | 47 | h <- define_out$handle 48 | customrequest <- define_out$customrequest 49 | 50 | response <- execute_search(self = self, url = url, handle = h, 51 | customrequest = customrequest, esearch, retries) 52 | 53 | return(response) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /R/search-sent-period-int.R: -------------------------------------------------------------------------------- 1 | #' Search by origination date (RFC-2822 Header - SENT Period) 2 | #' @param since_date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param before_date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 6 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 7 | #' objects, since IMAP servers use this unusual date format. 8 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 9 | #' CRITERIA". Default is \code{FALSE}. 10 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 11 | #' presented as message's sequence numbers. A message sequence number is a 12 | #' message's relative position to the oldest message in the mailbox. It may 13 | #' change after deleting or moving messages. If a message is deleted, sequence 14 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 15 | #' performed using the \code{"UID"} or unique identifier, and results are 16 | #' presented as such. UIDs are always the same during the life cycle of a message. 17 | #' @param flag Optional argument that sets one or more flags as an additional 18 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 19 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 20 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 21 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 22 | #' will condense the results: instead of writing down the whole sequences of messages' 23 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 24 | #' which decreases transmission costs. This argument can be used along with 25 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 26 | #' supports \code{ESEARCH} with 27 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 28 | #' @param retries Number of attempts to connect and execute the command. 29 | #' Default is \code{1}. 30 | #' @noRd 31 | search_sent_period_int <- function(self, since_date_char, before_date_char, negate, 32 | use_uid, flag, esearch, retries) { 33 | 34 | check_args(since_date_char = since_date_char, before_date_char = before_date_char, 35 | negate = negate, use_uid = use_uid, flag = flag, esearch = esearch, 36 | retries = retries) 37 | 38 | # forcing retries as an integer 39 | retries <- as.integer(retries) 40 | 41 | url <- self$con_params$url 42 | 43 | # isolating the handle 44 | h <- self$con_handle 45 | 46 | #define customrequest 47 | define_out <- define_searchrequest_period(operation1 = "SENTSINCE", 48 | since_date_char = since_date_char, 49 | operation2 = "SENTBEFORE", 50 | before_date_char = before_date_char, 51 | negate = negate, 52 | use_uid = use_uid, flag = flag, 53 | esearch = esearch, handle = h) 54 | 55 | h <- define_out$handle 56 | customrequest <- define_out$customrequest 57 | 58 | response <- execute_search(self = self, url = url, handle = h, 59 | customrequest = customrequest, esearch, retries) 60 | 61 | return(response) 62 | 63 | } 64 | -------------------------------------------------------------------------------- /R/search-sent-since-int.R: -------------------------------------------------------------------------------- 1 | #' Search by origination date (RFC-2822 Header - SENT SINCE) 2 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param flag Optional argument that sets one or more flags as an additional 15 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 16 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 17 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 18 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 19 | #' will condense the results: instead of writing down the whole sequences of messages' 20 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 21 | #' which decreases transmission costs. This argument can be used along with 22 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 23 | #' supports \code{ESEARCH} with 24 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 25 | #' @param retries Number of attempts to connect and execute the command. 26 | #' Default is \code{1}. 27 | #' @noRd 28 | search_sent_since_int <- function(self, date_char, negate, use_uid, flag, esearch, 29 | retries) { 30 | 31 | check_args(date_char = date_char, negate = negate, use_uid = use_uid, flag = flag, 32 | esearch = esearch, retries = retries) 33 | 34 | # forcing retries as an integer 35 | retries <- as.integer(retries) 36 | 37 | url <- self$con_params$url 38 | 39 | # isolating the handle 40 | h <- self$con_handle 41 | 42 | #define customrequest 43 | define_out <- define_searchrequest_date(operation = "SENTSINCE", 44 | date_char = date_char, negate = negate, 45 | use_uid = use_uid, flag = flag, esearch = esearch, 46 | handle = h) 47 | 48 | h <- define_out$handle 49 | customrequest <- define_out$customrequest 50 | 51 | response <- execute_search(self = self, url = url, handle = h, 52 | customrequest = customrequest, esearch, retries) 53 | 54 | return(response) 55 | 56 | } 57 | -------------------------------------------------------------------------------- /R/search-since-int.R: -------------------------------------------------------------------------------- 1 | #' Search by internal date (SINCE) (INTERNAL HELPER) 2 | #' @param date_char A \code{character string} with format "DD-Mon-YYYY", e.g. 3 | #' "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 4 | #' objects, since IMAP servers use this unusual date format. 5 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 6 | #' CRITERIA". Default is \code{FALSE}. 7 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 8 | #' presented as message's sequence numbers. A message sequence number is a 9 | #' message's relative position to the oldest message in the mailbox. It may 10 | #' change after deleting or moving messages. If a message is deleted, sequence 11 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 12 | #' performed using the \code{"UID"} or unique identifier, and results are 13 | #' presented as such. UIDs are always the same during the life cycle of a message. 14 | #' @param flag Optional argument that sets one or more flags as an additional 15 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 16 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 17 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 18 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 19 | #' will condense the results: instead of writing down the whole sequences of messages' 20 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 21 | #' which decreases transmission costs. This argument can be used along with 22 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 23 | #' supports \code{ESEARCH} with 24 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 25 | #' @param retries Number of attempts to connect and execute the command. 26 | #' Default is \code{1}. 27 | #' @noRd 28 | search_since_int <- function(self, date_char, negate, use_uid, 29 | flag, esearch, retries) { 30 | 31 | check_args(date_char = date_char, negate = negate, use_uid = use_uid, 32 | flag = flag, esearch = esearch, retries = retries) 33 | 34 | # forcing retries as an integer 35 | retries <- as.integer(retries) 36 | 37 | url <- self$con_params$url 38 | 39 | # isolating the handle 40 | h <- self$con_handle 41 | 42 | #define customrequest 43 | define_out <- define_searchrequest_date(operation = "SINCE", 44 | date_char = date_char, negate = negate, 45 | use_uid = use_uid, flag = flag, esearch = esearch, 46 | handle = h) 47 | 48 | h <- define_out$handle 49 | customrequest <- define_out$customrequest 50 | 51 | response <- execute_search(self = self, url = url, handle = h, 52 | customrequest = customrequest, esearch, retries) 53 | 54 | return(response) 55 | 56 | } 57 | -------------------------------------------------------------------------------- /R/search-smaller-than-int.R: -------------------------------------------------------------------------------- 1 | #' Search by size (SMALLER) (INTERNAL HELPER) 2 | #' @param size An integer specifying the size in bytes to be used as 3 | #' search criterion. 4 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 5 | #' CRITERIA". Default is \code{FALSE}. 6 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 7 | #' presented as message's sequence numbers. A message sequence number is a 8 | #' message's relative position to the oldest message in the mailbox. It may 9 | #' change after deleting or moving messages. If a message is deleted, sequence 10 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 11 | #' performed using the \code{"UID"} or unique identifier, and results are 12 | #' presented as such. UIDs are always the same during the life cycle of a message. 13 | #' @param flag Optional argument that sets one or more flags as an additional 14 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 15 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 16 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 17 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 18 | #' will condense the results: instead of writing down the whole sequences of messages' 19 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 20 | #' which decreases transmission costs. This argument can be used along with 21 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 22 | #' supports \code{ESEARCH} with 23 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 24 | #' @param retries Number of attempts to connect and execute the command. 25 | #' Default is \code{1}. 26 | #' @noRd 27 | search_smaller_than_int <- function(self, size, negate, use_uid, flag, esearch, 28 | retries) { 29 | 30 | check_args(size = size, negate = negate, use_uid = use_uid, flag = flag, 31 | esearch = esearch, retries = retries) 32 | 33 | # forcing retries as an integer 34 | retries <- as.integer(retries) 35 | 36 | url <- self$con_params$url 37 | 38 | # isolating the handle 39 | h <- self$con_handle 40 | 41 | #define customrequest 42 | define_out <- define_searchrequest_size(operation = "SMALLER", 43 | size = size, negate = negate, 44 | use_uid = use_uid, flag = flag, 45 | esearch = esearch, handle = h) 46 | 47 | h <- define_out$handle 48 | customrequest <- define_out$customrequest 49 | 50 | response <- execute_search(self = self, url = url, handle = h, 51 | customrequest = customrequest, esearch, retries) 52 | 53 | return(response) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /R/search-string-int.R: -------------------------------------------------------------------------------- 1 | #' Search by string or expression (INTERNAL HELPER) 2 | #' @param expr A character string specifying the word or expression to search 3 | #' for in messages. 4 | #' @param where A mandatory character string specifying in which 5 | #' message's Section or Header Field to search for the provided string. For 6 | #' some available options, see \code{\link{section_or_field_options}}. 7 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 8 | #' CRITERIA". Default is \code{FALSE}. 9 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 10 | #' presented as message's sequence numbers. A message sequence number is a 11 | #' message's relative position to the oldest message in the mailbox. It may 12 | #' change after deleting or moving messages. If a message is deleted, sequence 13 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 14 | #' performed using the \code{"UID"} or unique identifier, and results are 15 | #' presented as such. UIDs are always the same during the life cycle of a message. 16 | #' @param flag Optional argument that sets one or more flags as an additional 17 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 18 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 19 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 20 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 21 | #' will condense the results: instead of writing down the whole sequences of messages' 22 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 23 | #' which decreases transmission costs. This argument can be used along with 24 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 25 | #' supports \code{ESEARCH} with 26 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 27 | #' @param retries Number of attempts to connect and execute the command. 28 | #' Default is \code{1}. 29 | #' @noRd 30 | search_string_int <- function(self, expr, where = NULL, negate = FALSE, 31 | use_uid = FALSE, flag = NULL, esearch = FALSE, retries = 2) { 32 | 33 | 34 | # if ( (is.null(in_headerfield) && is.null(in_section)) || 35 | # (!is.null(in_headerfield) && !is.null(in_section)) ) { 36 | # stop('Chosse one argument: "in_headerfield" or "in_section".') 37 | # 38 | # } else if (!is.null(in_headerfield)) { 39 | # assertthat::assert_that( 40 | # is.character(in_headerfield), 41 | # msg='"in_headerfield" argument must be of type character. See headerfield_options().') 42 | # } else { 43 | # assertthat::assert_that( 44 | # is.character(in_section), 45 | # msg='"in_section" argument must be of type character.') 46 | # } 47 | 48 | check_args(expr = expr, where = where, negate = negate, use_uid = use_uid, 49 | flag = flag, esearch = esearch, retries = retries) 50 | 51 | # forcing retries as an integer 52 | retries <- as.integer(retries) 53 | 54 | url <- self$con_params$url 55 | 56 | # isolating the handle 57 | h <- self$con_handle 58 | 59 | #define customrequest 60 | define_out <- define_searchrequest_string(expr = expr, 61 | where = where, 62 | negate = negate, 63 | use_uid = use_uid, flag = flag, 64 | esearch = esearch, 65 | handle = h) 66 | 67 | h <- define_out$handle 68 | customrequest <- define_out$customrequest 69 | 70 | response <- execute_search(self = self, url = url, handle = h, 71 | customrequest = customrequest, esearch, retries) 72 | 73 | return(response) 74 | 75 | } 76 | -------------------------------------------------------------------------------- /R/search-younger-than-int.R: -------------------------------------------------------------------------------- 1 | #' Search WITHIN a time period (YOUNGER) (INTERNAL HELPER) 2 | #' @param seconds An integer specifying the number of seconds to be used as 3 | #' the search criterion. 4 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 5 | #' CRITERIA". Default is \code{FALSE}. 6 | #' @param use_uid Default is \code{FALSE}. In this case, results will be 7 | #' presented as message's sequence numbers. A message sequence number is a 8 | #' message's relative position to the oldest message in the mailbox. It may 9 | #' change after deleting or moving messages. If a message is deleted, sequence 10 | #' numbers are reordered to fill the gap. If \code{TRUE}, the command will be 11 | #' performed using the \code{"UID"} or unique identifier, and results are 12 | #' presented as such. UIDs are always the same during the life cycle of a message. 13 | #' @param flag Optional argument that sets one or more flags as an additional 14 | #' filter to the search. Use \href{#method-list_flags}{\code{ImapCon$list_flags()}} 15 | #' to list the flags in a selected mail folder. Default is \code{NULL}. 16 | #' @param esearch A logical. Default is \code{FALSE}. If the IMAP server has 17 | #' \code{ESEARCH} capability, it can be used to optimize search results. It 18 | #' will condense the results: instead of writing down the whole sequences of messages' 19 | #' ids, such as \code{\{1 2 3 4 5\}}, it will be presented as \code{\{1:5\}}, 20 | #' which decreases transmission costs. This argument can be used along with 21 | #' \code{buffersize} to avoid results stripping. Check if your IMAP server 22 | #' supports \code{ESEARCH} with 23 | #' \href{#method-list_server_capabilities}{\code{ImapCon$list_server_capabilities()}}. 24 | #' @param retries Number of attempts to connect and execute the command. 25 | #' Default is \code{1}. 26 | #' @noRd 27 | search_younger_than_int <- function(self, seconds, negate, use_uid, flag, esearch, 28 | retries) { 29 | 30 | check_args(seconds = seconds, negate = negate, use_uid = use_uid, flag = flag, 31 | esearch = esearch, retries = retries) 32 | 33 | # forcing retries as an integer 34 | retries <- as.integer(retries) 35 | 36 | url <- self$con_params$url 37 | 38 | # isolating the handle 39 | h <- self$con_handle 40 | 41 | #define customrequest 42 | define_out <- define_searchrequest_within(operation = "YOUNGER", 43 | seconds = seconds, negate = negate, 44 | use_uid = use_uid, flag = flag, esearch = esearch, 45 | handle = h) 46 | 47 | h <- define_out$handle 48 | customrequest <- define_out$customrequest 49 | 50 | response <- execute_search(self = self, url = url, handle = h, 51 | customrequest = customrequest, esearch, retries) 52 | 53 | return(response) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /R/select-folder-int.R: -------------------------------------------------------------------------------- 1 | #' Select a mail folder (INTERNAL HELPER). 2 | #' @param name A \code{character} string containing the name of an existing mail folder on the 3 | #' user's mailbox. 4 | #' @param mute A \code{logical}. Provides a confirmation message if the 5 | #' command is successfully executed. Default is \code{FALSE}. 6 | #' @param retries Number of attempts to connect and execute the command. Default 7 | #' is \code{1}. 8 | #' @noRd 9 | select_folder_int <- function(self, name, mute, retries) { 10 | 11 | check_args(name = name, mute = mute, retries = retries) # we have to pass 12 | #.. the argg as arg = arg, in order to the check_argg capture the names 13 | 14 | # forcing retries as an integer 15 | retries <- as.integer(retries) 16 | 17 | folder <- adjust_folder_name(name) 18 | # folder = name 19 | 20 | # self$imapconf$url <- utils::URLencode(gsub("/+$", "", self$url)) 21 | url <- self$con_params$url 22 | 23 | # isolating the handle 24 | h <- self$con_handle 25 | # h <- curl::new_handle() 26 | # do.call(curl::handle_setopt, c(h, con$self)) # da erro aqui. eh melhor passar o handle de self igual ele cria o 27 | # self$auth 28 | 29 | tryCatch({ 30 | curl::handle_setopt(h, customrequest = paste0('SELECT ', folder)) 31 | }, error = function(e){ 32 | stop("The connection handle is dead. Please, configure a new IMAP connection with configure_imap().") 33 | }) 34 | 35 | response <- tryCatch({ 36 | curl::curl_fetch_memory(url, handle = h) 37 | }, error = function(e){ 38 | # print(e$message) 39 | response_error_handling(e$message[1]) 40 | }) 41 | 42 | if(is.null(response)){ 43 | 44 | count_retries = 0 #the first try doesnt count 45 | 46 | # FORCE appending fresh_connect 47 | # curl::handle_setopt(handle = h, fresh_connect = TRUE) # parece que nao precisa, mas vamos deixar 48 | 49 | while (is.null(response) && count_retries < retries) { 50 | count_retries = count_retries + 1 51 | 52 | response <- tryCatch({ 53 | curl::curl_fetch_memory(url, handle = h) 54 | }, error = function(e){ 55 | # print(e$message) 56 | response_error_handling(e$message[1]) 57 | }) 58 | 59 | } 60 | 61 | if (is.null(response)) { 62 | 63 | stop('Request error: the server returned an error.') 64 | 65 | } else { # v0.3.2 66 | if (!mute) { 67 | if (self$con_params$verbose) { 68 | Sys.sleep(0.01) # wait for the end of the client-server conversation 69 | } 70 | cat(paste0("\n::mRpostman: ", '"', name, '"', " selected.\n")) # v0.3.2 71 | # using the folder name without any transformation 72 | } 73 | 74 | } 75 | 76 | } else { 77 | if (!mute) { 78 | if (self$con_params$verbose) { 79 | Sys.sleep(0.01) 80 | } 81 | cat(paste0("\n::mRpostman: ", '"', name, '"', " selected.\n")) # v0.3.2 82 | # using the folder name without any transformation 83 | } 84 | } 85 | 86 | 87 | invisible(name) 88 | # invisible(0L) 89 | 90 | } 91 | -------------------------------------------------------------------------------- /R/sent-before.R: -------------------------------------------------------------------------------- 1 | #' @inherit before 2 | #' @family custom search 3 | #' @examples 4 | #' \dontrun{ 5 | #' # select folder & search 6 | #' con$select_folder(name = "INBOX") 7 | #' # search for messages SINCE "30-Ago-2019" AND SMALLER than 512KB. 8 | #' res <- con$search(request = AND(sent_since(date_char = "30-Ago-2019"), 9 | #' smaller_than(size = 512000))) 10 | #' } 11 | #' @export 12 | #' 13 | sent_before <- function(date_char, negate = FALSE) { 14 | 15 | 16 | check_args(date_char, negate) 17 | 18 | # setting part of the search string 19 | 20 | if (!isTRUE(negate)) { 21 | out = paste0('(SENTBEFORE ', date_char, ')') 22 | 23 | } else { 24 | out = paste0('(NOT (SENTBEFORE ', date_char, '))') 25 | 26 | } 27 | 28 | return(out) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /R/sent-on.R: -------------------------------------------------------------------------------- 1 | #' @inherit before 2 | #' @family custom search 3 | #' @examples 4 | #' \dontrun{ 5 | #' # select folder & search 6 | #' con$select_folder(name = "INBOX") 7 | #' # search for messages SINCE "30-Ago-2019" OR LARGER than 512KB. 8 | #' res <- con$search(request = OR(sent_since(date_char = "30-Jun-2020"), 9 | #' larger_than(size = 512000))) 10 | #' } 11 | #' @export 12 | #' 13 | sent_on <- function(date_char, negate = FALSE) { 14 | 15 | 16 | check_args(date_char, negate) 17 | 18 | # setting part of the search string 19 | 20 | if (!isTRUE(negate)) { 21 | out = paste0('(SENTON ', date_char, ')') 22 | 23 | } else { 24 | out = paste0('(NOT (SENTON ', date_char, '))') 25 | 26 | } 27 | 28 | return(out) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /R/sent-since.R: -------------------------------------------------------------------------------- 1 | #' @inherit before 2 | #' @family custom search 3 | #' @examples 4 | #' \dontrun{ 5 | #' # select folder & search 6 | #' con$select_folder(name = "INBOX") 7 | #' # search for messages SENT SINCE "22-Mar-2020" OR containing the STRING 8 | #' # "congratulations" in the subject. 9 | #' res <- con$search(request = AND(sent_since(date_char = "22-Mar-2020"), 10 | #' string(expr = "congratulations", 11 | #' where = "SUBJECT"))) 12 | #' } 13 | #' @export 14 | #' 15 | sent_since <- function(date_char, negate = FALSE) { 16 | 17 | 18 | check_args(date_char, negate) 19 | 20 | # setting part of the search string 21 | 22 | if (!isTRUE(negate)) { 23 | out = paste0('(SENTSINCE ', date_char, ')') 24 | 25 | } else { 26 | out = paste0('(NOT (SENTSINCE ', date_char, '))') 27 | 28 | } 29 | 30 | return(out) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /R/serialize-filename.R: -------------------------------------------------------------------------------- 1 | #' Add sufix to a filename if it already exists in local folder 2 | #' @param prefix A character string with a message content. 3 | #' @noRd 4 | serialize_filename = function(sufix, complete_path){ 5 | # sol: https://stackoverflow.com/questions/25429557/how-to-create-a-new-output-file-in-r-if-a-file-with-that-name-already-exists 6 | complete_path_with_filename <- paste0(complete_path, "/", sufix) 7 | 8 | if(!file.exists(complete_path_with_filename)){return(complete_path_with_filename)} 9 | i=1 10 | repeat { 11 | # f = paste(prefix,i,sep="_") 12 | # f = paste0(sufix, "(", i, ")") 13 | # f = paste0("(", i, ")", sufix) 14 | complete_path_with_filename <- paste0(complete_path, "/", "(", i, ")", sufix) 15 | if(!file.exists(complete_path_with_filename)){return(complete_path_with_filename)} 16 | i=i+1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /R/since.R: -------------------------------------------------------------------------------- 1 | #' @inherit before 2 | #' @family custom search 3 | #' @examples 4 | #' \dontrun{ 5 | #' # select folder & search 6 | #' con$select_folder(name = "INBOX") 7 | #' # search for messages SINCE "17-Apr-2019" AND SMALLER than 512KB. 8 | #' res <- con$search(request = AND(since(date_char = "17-Apr-2019"), 9 | #' smaller_than(size = 512000))) 10 | #' } 11 | #' @export 12 | #' 13 | since <- function(date_char, negate = FALSE) { 14 | 15 | 16 | check_args(date_char, negate) 17 | 18 | # setting part of the search string 19 | 20 | if (!isTRUE(negate)) { 21 | out = paste0('(SINCE ', date_char, ')') 22 | 23 | } else { 24 | out = paste0('(NOT (SINCE ', date_char, '))') 25 | 26 | } 27 | 28 | return(out) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /R/smaller-than.R: -------------------------------------------------------------------------------- 1 | #' Criterion constructor function to be combined in a custom search statement 2 | #' @param size An integer specifying the number of seconds to be used as 3 | #' search criterion. 4 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 5 | #' CRITERIA". Default is \code{FALSE}. 6 | #' @family custom search 7 | #' @examples 8 | #' \dontrun{ 9 | #' # select folder & search 10 | #' con$select_folder(name = "INBOX") 11 | #' # search for messages containing the string "XYZ@@k-state.edu" in the 12 | #' # "FROM" field OR those that are SMALLER than 512KB. 13 | #' res <- con$search(request = OR(string(expr = "XYZ@@k-state.edu", 14 | #' where = "FROM"), 15 | #' smaller_than(size = 512000))) 16 | #' } 17 | #' 18 | #' @export 19 | #' 20 | smaller_than <- function(size, negate = FALSE) { 21 | 22 | check_args(size, negate) 23 | 24 | # setting part of the search string 25 | 26 | if (!isTRUE(negate)) { 27 | out = paste0('(SMALLER ', size, ')') 28 | 29 | } else { 30 | out = paste0('(NOT (SMALLER ', size, '))') 31 | 32 | } 33 | 34 | return(out) 35 | 36 | } 37 | -------------------------------------------------------------------------------- /R/string.R: -------------------------------------------------------------------------------- 1 | #' Criterion constructor function to be combined in a custom search statement 2 | #' @param expr A character string specifying the word or expression to search 3 | #' for in messages. 4 | #' @param where A mandatory character string specifying in which 5 | #' message's Section or Header Field to search for the provided string. 6 | #' @param negate If \code{TRUE}, negates the search and seeks for "NOT SEARCH 7 | #' CRITERIA". Default is \code{FALSE}. 8 | #' @family custom search 9 | #' @examples 10 | #' \dontrun{ 11 | #' # select folder & search 12 | #' con$select_folder(name = "INBOX") 13 | #' # search for messages containing the string "XYZ@@k-state.edu" in the 14 | #' # "FROM" AND the string "@@gmail.com" in the "CC" field. 15 | #' res <- con$search(request = AND(string(expr = "XYZ@@k-state.edu", 16 | #' where = "FROM"), 17 | #' string(expr = "@@gmail.com", 18 | #' where = "CC"))) 19 | #' } 20 | #' 21 | #' @export 22 | #' 23 | string <- function(expr, where, negate = FALSE) { 24 | 25 | # Note to self: all helper functions (even internal) should NOT be declared as 26 | #.. methods in the R6 class !!! 27 | 28 | # section_or_field = toupper(section_or_field) 29 | 30 | check_args(expr = expr, where = where, negate = negate) 31 | 32 | # setting part of the search string 33 | section_or_field = where # one is going to be NULL 34 | 35 | 36 | if (!isTRUE(negate)) { 37 | out = paste0('(', section_or_field, ' ', paste0('"', expr, '"'), ')') 38 | 39 | } else { 40 | out = paste0('(NOT (', section_or_field, ' ', paste0('"', expr, '"'), '))') 41 | 42 | } 43 | 44 | return(out) 45 | 46 | } 47 | -------------------------------------------------------------------------------- /R/younger-than.R: -------------------------------------------------------------------------------- 1 | #' @inherit older_than 2 | #' @note To be able to use this functionality, the server must support the 3 | #' \code{WITHIN} capability. 4 | #' @family custom search 5 | #' @examples 6 | #' \dontrun{ 7 | #' # select folder & search 8 | #' con$select_folder(name = "INBOX") 9 | #' # search for messages containing the string "XYZ@@k-state.edu" in the 10 | #' # "FROM" field AND those that are YOUNGER than 3600 seconds (1 hour). 11 | #' res <- con$search(request = AND(string(expr = "XYZ@@k-state.edu", 12 | #' where = "FROM"), 13 | #' younger_than(seconds = 3600))) 14 | #' } 15 | #' 16 | #' @export 17 | #' 18 | younger_than <- function(seconds, negate = FALSE) { 19 | 20 | check_args(seconds, negate) 21 | 22 | # setting part of the search string 23 | 24 | if (!isTRUE(negate)) { 25 | out = paste0('(YOUNGER ', seconds, ')') 26 | 27 | } else { 28 | out = paste0('(NOT (YOUNGER ', seconds, '))') 29 | 30 | } 31 | 32 | return(out) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onAttach <- function(libname, pkgname) { 2 | packageStartupMessage("Please do not forget to appropriately cite 'mRpostman' when using it in an academic research. See citation(package = 'mRpostman').") 3 | } 4 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: ~ 2 | 3 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | **mRpostman - Update to v1.1.4** 2 | 3 | ## Test environments 4 | * local Ubuntu 20.04, R release 5 | * local Windows 10, R release 6 | * win-builder: devel, release & oldrelease 7 | * Github Actions, devel & release 8 | 9 | ## R CMD check results 10 | 0 ERRORs, 0 WARNINGs, 0 NOTEs 11 | -------------------------------------------------------------------------------- /docs/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step1_1.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step1_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step1_1x.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_1x.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_2x.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_3.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_x1.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_x2.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_x3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_x3x.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_x4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_x4.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_x5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_x5.png -------------------------------------------------------------------------------- /docs/articles/figures/xoauth/step2_x6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/articles/figures/xoauth/step2_x6.png -------------------------------------------------------------------------------- /docs/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/favicon-16x16.png -------------------------------------------------------------------------------- /docs/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/favicon-32x32.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/favicon.ico -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/logo.png -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $(".examples, div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent; 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 2.19.2 2 | pkgdown: 1.6.1 3 | pkgdown_sha: ~ 4 | articles: 5 | basics: basics.html 6 | code_migration: code_migration.html 7 | xoauth2.0: xoauth2.0.html 8 | last_built: 2024-09-17T15:49Z 9 | 10 | -------------------------------------------------------------------------------- /docs/reference/figures/aol1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/aol1.png -------------------------------------------------------------------------------- /docs/reference/figures/aol2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/aol2.png -------------------------------------------------------------------------------- /docs/reference/figures/aol3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/aol3.png -------------------------------------------------------------------------------- /docs/reference/figures/gmail1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/gmail1.png -------------------------------------------------------------------------------- /docs/reference/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/logo.png -------------------------------------------------------------------------------- /docs/reference/figures/yahoo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/yahoo1.png -------------------------------------------------------------------------------- /docs/reference/figures/yahoo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/yahoo2.png -------------------------------------------------------------------------------- /docs/reference/figures/yahoo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/docs/reference/figures/yahoo3.png -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | ## R package reference generated from DESCRIPTION metadata 2 | 3 | bibentry( 4 | "Article", 5 | title = "mRpostman: An IMAP Client for R", 6 | author = "Allan V. C. Quadros", 7 | year = 2024, 8 | journal = "Journal of Open Research Software", 9 | volume = 12, 10 | number = 1, 11 | pages = 4, 12 | doi = "10.5334/jors.480", 13 | ) 14 | 15 | citation(auto = meta) 16 | 17 | 18 | -------------------------------------------------------------------------------- /mRpostman.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageCheckArgs: --as-cran 22 | PackageRoxygenize: rd,collate,namespace 23 | -------------------------------------------------------------------------------- /man/AND.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/AND.R 3 | \name{AND} 4 | \alias{AND} 5 | \title{Relational-operator-function to construct a custom search statement} 6 | \usage{ 7 | AND(..., negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{...}{a combination of criteria constructor functions with its arguments.} 11 | 12 | \item{negate}{If \code{TRUE}, negates the search and seeks for 13 | "NOT search_criterion". Default is \code{FALSE}.} 14 | } 15 | \value{ 16 | A search string to be used as a \code{request} parameter in 17 | \code{ImapCon$search()} function. 18 | } 19 | \description{ 20 | Relational-operator-function to construct a custom search statement 21 | } 22 | \examples{ 23 | \dontrun{ 24 | # select folder & search 25 | con$select_folder(name = "INBOX") 26 | # search for messages SINCE "30-Ago-2019" AND SMALLER than 512KB. 27 | res <- con$search(request = AND(sent_since(date_char = "30-Ago-2019"), 28 | smaller_than(size = 512000))) 29 | } 30 | } 31 | \seealso{ 32 | Other custom search: 33 | \code{\link{ImapCon}}, 34 | \code{\link{OR}()}, 35 | \code{\link{before}()}, 36 | \code{\link{flag}()}, 37 | \code{\link{larger_than}()}, 38 | \code{\link{older_than}()}, 39 | \code{\link{on}()}, 40 | \code{\link{sent_before}()}, 41 | \code{\link{sent_on}()}, 42 | \code{\link{sent_since}()}, 43 | \code{\link{since}()}, 44 | \code{\link{smaller_than}()}, 45 | \code{\link{string}()}, 46 | \code{\link{younger_than}()} 47 | } 48 | \concept{custom search} 49 | -------------------------------------------------------------------------------- /man/OR.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/OR.R 3 | \name{OR} 4 | \alias{OR} 5 | \title{Relational-operator-function to construct a custom search statement} 6 | \usage{ 7 | OR(..., negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{...}{a combination of criteria constructor functions with its arguments.} 11 | 12 | \item{negate}{If \code{TRUE}, negates the search and seeks for 13 | "NOT search_criterion". Default is \code{FALSE}.} 14 | } 15 | \value{ 16 | A search string to be used as a \code{request} parameter in 17 | \code{ImapCon$search()} function. 18 | } 19 | \description{ 20 | Relational-operator-function to construct a custom search statement 21 | } 22 | \examples{ 23 | \dontrun{ 24 | # select folder & search 25 | con$select_folder(name = "INBOX") 26 | # search for messages SINCE "30-Ago-2019" OR SMALLER than 512KB. 27 | res <- con$search(request = OR(sent_since(date_char = "30-Ago-2019"), 28 | smaller_than(size = 512000))) 29 | } 30 | } 31 | \seealso{ 32 | Other custom search: 33 | \code{\link{AND}()}, 34 | \code{\link{ImapCon}}, 35 | \code{\link{before}()}, 36 | \code{\link{flag}()}, 37 | \code{\link{larger_than}()}, 38 | \code{\link{older_than}()}, 39 | \code{\link{on}()}, 40 | \code{\link{sent_before}()}, 41 | \code{\link{sent_on}()}, 42 | \code{\link{sent_since}()}, 43 | \code{\link{since}()}, 44 | \code{\link{smaller_than}()}, 45 | \code{\link{string}()}, 46 | \code{\link{younger_than}()} 47 | } 48 | \concept{custom search} 49 | -------------------------------------------------------------------------------- /man/before.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/before.R 3 | \name{before} 4 | \alias{before} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | before(date_char, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{date_char}{A \code{character string} with format "DD-Mon-YYYY", e.g. 11 | "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 12 | objects, since IMAP servers use this unusual date format.} 13 | 14 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 15 | CRITERIA". Default is \code{FALSE}.} 16 | } 17 | \value{ 18 | A search string to be used as a \code{request} parameter in 19 | \code{ImapCon$search()} function. 20 | } 21 | \description{ 22 | Criterion constructor function to be combined in a custom search statement 23 | } 24 | \examples{ 25 | \dontrun{ 26 | # select folder & search 27 | con$select_folder(name = "INBOX") 28 | # search for messages BEFORE "17-Apr-2019" AND NOT SMALLER than 512KB. 29 | res <- con$search(request = AND(before(date_char = "17-Apr-2019"), 30 | smaller_than(size = 512000, negate = TRUE))) 31 | } 32 | } 33 | \seealso{ 34 | Other custom search: 35 | \code{\link{AND}()}, 36 | \code{\link{ImapCon}}, 37 | \code{\link{OR}()}, 38 | \code{\link{flag}()}, 39 | \code{\link{larger_than}()}, 40 | \code{\link{older_than}()}, 41 | \code{\link{on}()}, 42 | \code{\link{sent_before}()}, 43 | \code{\link{sent_on}()}, 44 | \code{\link{sent_since}()}, 45 | \code{\link{since}()}, 46 | \code{\link{smaller_than}()}, 47 | \code{\link{string}()}, 48 | \code{\link{younger_than}()} 49 | } 50 | \concept{custom search} 51 | -------------------------------------------------------------------------------- /man/clean_msg_text.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/clean-msg-text.R 3 | \name{clean_msg_text} 4 | \alias{clean_msg_text} 5 | \title{Extract text from MIME level} 6 | \usage{ 7 | clean_msg_text(msg_list) 8 | } 9 | \arguments{ 10 | \item{msg_list}{A \code{list} with the MIME level 1 of the body or text content 11 | of the messages fetched with \href{#method-fetch_body}{\code{ImapCon$fetch_body()}} or 12 | \href{#method-fetch_text}{\code{ImapCon$fetch_text()}}.} 13 | } 14 | \value{ 15 | A \code{list} containing the decoded messages if applicable. 16 | } 17 | \description{ 18 | Extract text from MIME level 19 | } 20 | \examples{ 21 | \dontrun{ 22 | ids <- con$search_since(date_char = "01-Apr-2020", use_uid = TRUE) 23 | 24 | fetch_res <- ids \%>\% 25 | con$fetch_body(use_uid = TRUE, mime_level = 1L) 26 | 27 | clean_text_list <- clean_msg_text(msg_list = fetch_res) 28 | } 29 | } 30 | \references{ 31 | Moore, K. (1996), MIME (Multipurpose Internet Mail Extensions) Part 32 | Three: Message Header Extensions for Non-ASCII 33 | Text, RFC 2047, November 1996, https://tools.ietf.org/html/rfc2047. 34 | 35 | Freed, N., Borenstein, N. (1996), Multipurpose Internet Mail Extensions 36 | (MIME) Part One: Format of Internet Message Bodies, RFC 2045, November 1996, 37 | https://tools.ietf.org/html/rfc2045. 38 | 39 | Internal parts of this object, regarding the quoted printable type, 40 | were borrowed from https://github.com/hrbrmstr/hrbrmisc/blob/master/R/qp.r with 41 | slight modifications. 42 | } 43 | -------------------------------------------------------------------------------- /man/configure_imap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/configure-imap.R 3 | \name{configure_imap} 4 | \alias{configure_imap} 5 | \title{IMAP Connection Configuration} 6 | \usage{ 7 | configure_imap( 8 | url, 9 | username, 10 | password = NULL, 11 | xoauth2_bearer = NULL, 12 | use_ssl = TRUE, 13 | verbose = FALSE, 14 | buffersize = 16000, 15 | timeout_ms = 0, 16 | ... 17 | ) 18 | } 19 | \arguments{ 20 | \item{url}{A character string containing the IMAP server address} 21 | 22 | \item{username}{A character string containing the username.} 23 | 24 | \item{password}{A character string containing the user's password.} 25 | 26 | \item{xoauth2_bearer}{A character string containing the oauth2 bearer token.} 27 | 28 | \item{use_ssl}{A logical indicating the use or not of Secure Sockets Layer 29 | encryption when connecting to the IMAP server. Default is \code{TRUE}.} 30 | 31 | \item{verbose}{If \code{FALSE}, mutes the flow of information between the 32 | server and the client. Default is \code{FALSE}.} 33 | 34 | \item{buffersize}{The size in bytes for the receive buffer. Default is 35 | 16000 bytes or 16kb, which means it will use the libcurl's default value. 36 | According to the libcurl's documentation, the maximum buffersize is 512kb 37 | (or 512000 bytes), but any number passed to \code{buffersize} is treated 38 | as a request, not an order.} 39 | 40 | \item{timeout_ms}{Time in milliseconds (ms) to wait for the execution or 41 | re-execution of a command. Default is 0, which means that no timeout limit is 42 | set.} 43 | 44 | \item{...}{Further curl parameters (see \code{curl::curl_options}) that 45 | can be used with the IMAP protocol. Only for advanced users.} 46 | } 47 | \value{ 48 | A new `ImapCon` object. 49 | } 50 | \description{ 51 | Configure and create a new IMAP connection. 52 | } 53 | \examples{ 54 | \dontrun{ 55 | # w/ Plain authentication 56 | con <- configure_imap( 57 | url="imaps://outlook.office365.com", 58 | username="user@agency.gov.br", 59 | password=rstudioapi::askForPassword(), 60 | verbose = TRUE) 61 | 62 | # w/ OAuth2.0 authentication 63 | con <- configure_imap( 64 | url="imaps://outlook.office365.com", 65 | username="user@agency.gov.br", 66 | verbose = TRUE, 67 | xoauth2_bearer = "XX.Ya9...") 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /man/decode_mime_header.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/decode-mime-header.R 3 | \name{decode_mime_header} 4 | \alias{decode_mime_header} 5 | \title{Decode RFC 2047 quoted-printable and base64 MIME headers and strings} 6 | \usage{ 7 | decode_mime_header(string) 8 | } 9 | \arguments{ 10 | \item{string}{A \code{character} vector containing a string to be decoded.} 11 | } 12 | \value{ 13 | A decoded \code{character} vector if applicable. 14 | } 15 | \description{ 16 | Decode RFC 2047 quoted-printable and base64 MIME headers and strings 17 | } 18 | \note{ 19 | The RFC 2047 (Moore, 1996) presents an encoded-word syntax to be used by e-mail 20 | clients to display body text and header information in character sets 21 | other than ASCII. According to the manual, non-ASCII content is encoded as 22 | an ASCII text string as follows: \code{=????=}. 23 | The encoding can be of two types: "B" for "BASE64", or "Q" for quoted- 24 | printable content (Freed and Borentein, 1996). Besides the standard RFC 2047 25 | decoding, this function also enables users to decode content that does not 26 | strictly follow the \code{=????=} RFC 2047 27 | syntax, i.e. cases where only the encoded text part is present, such as the 28 | quoted-printable pattern in the string \code{"Estat=EDstica"} (Estatística, 29 | which is the equivalent word, in Portuguese, for Statistics). 30 | } 31 | \examples{ 32 | \dontrun{ 33 | # The examples below runs smoothly on any computer. The 'dontrun' flag is just to skip CRAN checks. 34 | 35 | # Simple quoted-printable string - Portuguese example 36 | qp_encoded <- "Minist=E9rio_da_Educa=E7=E3o" 37 | decode_mime_header(string = qp_encoded) 38 | 39 | # Simple quoted-printable string - French example 40 | qp_encoded <- "sur la route =C3=A0 suivre les voil=C3=A0 bient=C3=B4t qui te d=C3=A9gradent" 41 | decode_mime_header(string = qp_encoded) 42 | 43 | # Simple quoted-printable string - Norwegian example 44 | qp_encoded <- "p=C3=A5 veien for =C3=A5 f=C3=B8lge, snart vil de forringe deg" 45 | decode_mime_header(string = qp_encoded) 46 | 47 | # Simple quoted-printable string - Turkish example 48 | qp_encoded <- "yak=C4=B1nda seni k=C3=BC=C3=A7=C3=BCk d=C3=BC=C5=9F=C3=BCrecekler" 49 | decode_mime_header(string = qp_encoded) 50 | 51 | # RFC 2047 quoted-printable header - Portuguese example 52 | qp_encoded <- "=?iso-8859-1?Q?DIDEC_Capacita=E7=E3o?=" 53 | decode_mime_header(string = qp_encoded) 54 | 55 | # RFC 2047 quoted-printable - German example 56 | qp_encoded <- "=?UTF-8?Q?stern=2Ede_-_t=C3=A4glich?=" 57 | decode_mime_header(string = qp_encoded) 58 | 59 | # RFC 2047 base64 - Portuguese example 60 | b64_encoded <- "=?utf-8?B?Sk9BTkEgRlVTQ08gTE9CTyBubyBUZWFtcw==?=" 61 | decode_mime_header(string = b64_encoded) 62 | } 63 | 64 | } 65 | \references{ 66 | Moore, K. (1996), MIME (Multipurpose Internet Mail Extensions) Part 67 | Three: Message Header Extensions for Non-ASCII 68 | Text, RFC 2047, November 1996, https://tools.ietf.org/html/rfc2047. 69 | 70 | Freed, N., Borenstein, N. (1996), Multipurpose Internet Mail Extensions 71 | (MIME) Part One: Format of Internet Message Bodies, RFC 2045, November 1996, 72 | https://tools.ietf.org/html/rfc2045. 73 | 74 | Internal parts of this object, regarding the quoted printable type, 75 | were borrowed from https://github.com/hrbrmstr/hrbrmisc/blob/master/R/qp.r with 76 | slight modifications. 77 | } 78 | -------------------------------------------------------------------------------- /man/figures/aol1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/aol1.png -------------------------------------------------------------------------------- /man/figures/aol2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/aol2.png -------------------------------------------------------------------------------- /man/figures/aol3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/aol3.png -------------------------------------------------------------------------------- /man/figures/gmail1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/gmail1.png -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/logo.png -------------------------------------------------------------------------------- /man/figures/yahoo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/yahoo1.png -------------------------------------------------------------------------------- /man/figures/yahoo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/yahoo2.png -------------------------------------------------------------------------------- /man/figures/yahoo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/man/figures/yahoo3.png -------------------------------------------------------------------------------- /man/flag.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/flag.R 3 | \name{flag} 4 | \alias{flag} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | flag(name, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{name}{A string containing one or more flags to search for. Use 11 | \href{#method-list_flags}{\code{ImapCon$list_flags()}} to list the flags 12 | in a selected mail folder.} 13 | 14 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 15 | CRITERIA". Default is \code{FALSE}.} 16 | } 17 | \description{ 18 | Criterion constructor function to be combined in a custom search statement 19 | } 20 | \examples{ 21 | \dontrun{ 22 | # select folder & search 23 | con$select_folder(name = "INBOX") 24 | # search for messages with Flag "UNSEEN" AND NOT Smaller Than 512KB. 25 | res <- con$search(request = AND(flag("UNSEEN"), 26 | smaller_than(size = 512000, negate = TRUE))) 27 | } 28 | } 29 | \seealso{ 30 | Other custom search: 31 | \code{\link{AND}()}, 32 | \code{\link{ImapCon}}, 33 | \code{\link{OR}()}, 34 | \code{\link{before}()}, 35 | \code{\link{larger_than}()}, 36 | \code{\link{older_than}()}, 37 | \code{\link{on}()}, 38 | \code{\link{sent_before}()}, 39 | \code{\link{sent_on}()}, 40 | \code{\link{sent_since}()}, 41 | \code{\link{since}()}, 42 | \code{\link{smaller_than}()}, 43 | \code{\link{string}()}, 44 | \code{\link{younger_than}()} 45 | } 46 | \concept{custom search} 47 | -------------------------------------------------------------------------------- /man/larger_than.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/larger-than.R 3 | \name{larger_than} 4 | \alias{larger_than} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | larger_than(size, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{size}{An integer specifying the number of seconds to be used as 11 | search criterion.} 12 | 13 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 14 | CRITERIA". Default is \code{FALSE}.} 15 | } 16 | \description{ 17 | Criterion constructor function to be combined in a custom search statement 18 | } 19 | \examples{ 20 | \dontrun{ 21 | # select folder & search 22 | con$select_folder(name = "INBOX") 23 | # search for messages containing the string "XYZ@k-state.edu" in the 24 | # "FROM" field OR those that are LARGER than 512KB. 25 | res <- con$search(request = OR(string(expr = "XYZ@k-state.edu", 26 | where = "FROM"), 27 | larger_than(size = 512000))) 28 | } 29 | 30 | } 31 | \seealso{ 32 | Other custom search: 33 | \code{\link{AND}()}, 34 | \code{\link{ImapCon}}, 35 | \code{\link{OR}()}, 36 | \code{\link{before}()}, 37 | \code{\link{flag}()}, 38 | \code{\link{older_than}()}, 39 | \code{\link{on}()}, 40 | \code{\link{sent_before}()}, 41 | \code{\link{sent_on}()}, 42 | \code{\link{sent_since}()}, 43 | \code{\link{since}()}, 44 | \code{\link{smaller_than}()}, 45 | \code{\link{string}()}, 46 | \code{\link{younger_than}()} 47 | } 48 | \concept{custom search} 49 | -------------------------------------------------------------------------------- /man/list_attachments.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/list-attachments.R 3 | \name{list_attachments} 4 | \alias{list_attachments} 5 | \title{List attachments and content-disposition types} 6 | \usage{ 7 | list_attachments(msg_list) 8 | } 9 | \arguments{ 10 | \item{msg_list}{A \code{list} containing the messages (body or text) fetched 11 | from the server.} 12 | } 13 | \value{ 14 | A \code{list} of \code{data.frames} containing the filenames and its 15 | \code{Content-Disposition} types for each fetched message. 16 | } 17 | \description{ 18 | List attachments and content-disposition types 19 | } 20 | \note{ 21 | Please, note that this is an independent function and not an R6 method 22 | that depends on the connection object. Therefore, it should be called alone 23 | without the ImapCon object. 24 | } 25 | \examples{ 26 | \dontrun{ 27 | con$select_folder(name = "INBOX") 28 | # do a search followed by a fetch operation, then extract the attachments' list 29 | out <- con$search_string(expr = "@k-state.edu", where = "FROM") \%>\% 30 | con$fetch_body() 31 | att_list <- list_attachments(msg_list = out) 32 | 33 | # or 34 | att_list <- con$search_string(expr = "@k-state.edu", where = "FROM") \%>\% 35 | con$fetch_body() \%>\% 36 | list_attachments() 37 | } 38 | } 39 | \seealso{ 40 | Other attachments: 41 | \code{\link{ImapCon}} 42 | } 43 | \concept{attachments} 44 | -------------------------------------------------------------------------------- /man/mRpostman-package.Rd: -------------------------------------------------------------------------------- 1 | \docType{package} 2 | \name{mRpostman-package} 3 | \alias{mRpostman-package} 4 | \alias{mRpostman} 5 | \title{An IMAP client for R} 6 | 7 | \description{ 8 | \pkg{mRpostman} is an easy-to-use IMAP client that provides tools for message searching, 9 | selective fetching of message attributes, mailbox management, attachment extraction, 10 | and several other IMAP features, paving the way for e-mail data analysis in \R. 11 | } 12 | 13 | 14 | \author{ 15 | 16 | Author & Mantainer: Allan Quadros \email{allanvcq@gmail.com} 17 | 18 | } 19 | 20 | \references{ 21 | 22 | Crispin, M. (2003), \emph{INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1}, RFC 3501, March 2003, \url{https://www.rfc-editor.org/rfc/rfc3501}. 23 | 24 | Heinlein, P. and Hartleben, P. (2008). \emph{The Book of IMAP: Building a Mail Server with Courier and Cyrus}. No Starch Press. ISBN 978-1-59327-177-0. 25 | 26 | Ooms, J. (2020). \emph{curl: A Modern and Flexible Web Client for R}. R package version 4.3, \url{https://CRAN.R-project.org/package=curl}. 27 | 28 | Stenberg, D. \emph{Libcurl - The Multiprotocol File Transfer Library}, \url{https://curl.se/libcurl/}. 29 | 30 | } 31 | 32 | \seealso{ 33 | 34 | Useful links: 35 | 36 | \itemize{ 37 | \item{ \code{mRpostman official website}: \url{https://allanvc.github.io/mRpostman/}} 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /man/metadata_options.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/metadata-options.R 3 | \name{metadata_options} 4 | \alias{metadata_options} 5 | \title{Message Metadata Options} 6 | \usage{ 7 | metadata_options() 8 | } 9 | \value{ 10 | A \code{vector} containing message metadata fields. 11 | } 12 | \description{ 13 | List Metadata fields used in messages. 14 | } 15 | \note{ 16 | This function lists message metadata used by 17 | IMAP servers, according to the RFC 2060 (Crispin, 1996). 18 | } 19 | \examples{ 20 | \dontrun{ 21 | 22 | library(mRpostman) 23 | metadata_options() 24 | 25 | } 26 | } 27 | \references{ 28 | Crispin, M., "Internet Message Access Protocol - Version 4rev1", 29 | RFC 2060, \doi{10.17487/RFC2060}, December 1996, 30 | \url{https://www.rfc-editor.org/info/rfc2060}. 31 | } 32 | \concept{options} 33 | -------------------------------------------------------------------------------- /man/older_than.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/older-than.R 3 | \name{older_than} 4 | \alias{older_than} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | older_than(seconds, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{seconds}{An integer specifying the number of seconds to be used as 11 | the search criterion.} 12 | 13 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 14 | CRITERIA". Default is \code{FALSE}.} 15 | } 16 | \description{ 17 | Criterion constructor function to be combined in a custom search statement 18 | } 19 | \note{ 20 | To be able to use this functionality, the server must support the 21 | \code{WITHIN} capability. 22 | } 23 | \examples{ 24 | \dontrun{ 25 | # select folder & search 26 | con$select_folder(name = "INBOX") 27 | # search for messages containing the string "XYZ@k-state.edu" in the 28 | # "FROM" field AND those that are OLDER than 3600 seconds (1 hour). 29 | res <- con$search(request = AND(string(expr = "XYZ@k-state.edu", 30 | where = "FROM"), 31 | older_than(seconds = 3600))) 32 | } 33 | 34 | } 35 | \seealso{ 36 | Other custom search: 37 | \code{\link{AND}()}, 38 | \code{\link{ImapCon}}, 39 | \code{\link{OR}()}, 40 | \code{\link{before}()}, 41 | \code{\link{flag}()}, 42 | \code{\link{larger_than}()}, 43 | \code{\link{on}()}, 44 | \code{\link{sent_before}()}, 45 | \code{\link{sent_on}()}, 46 | \code{\link{sent_since}()}, 47 | \code{\link{since}()}, 48 | \code{\link{smaller_than}()}, 49 | \code{\link{string}()}, 50 | \code{\link{younger_than}()} 51 | } 52 | \concept{custom search} 53 | -------------------------------------------------------------------------------- /man/on.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/on.R 3 | \name{on} 4 | \alias{on} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | on(date_char, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{date_char}{A \code{character string} with format "DD-Mon-YYYY", e.g. 11 | "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 12 | objects, since IMAP servers use this unusual date format.} 13 | 14 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 15 | CRITERIA". Default is \code{FALSE}.} 16 | } 17 | \value{ 18 | A search string to be used as a \code{request} parameter in 19 | \code{ImapCon$search()} function. 20 | } 21 | \description{ 22 | Criterion constructor function to be combined in a custom search statement 23 | } 24 | \examples{ 25 | \dontrun{ 26 | # select folder & search 27 | con$select_folder(name = "INBOX") 28 | # search for messages SINCE "17-Apr-2019" AND SMALLER than 512KB. 29 | res <- con$search(request = OR(on(date_char = "30-Jun-2019"), 30 | on(date_char = "22-Mar-2018"))) 31 | # search for messages received ON "30-Jun-2019" OR ON "22-Mar-2018". 32 | 33 | } 34 | } 35 | \seealso{ 36 | Other custom search: 37 | \code{\link{AND}()}, 38 | \code{\link{ImapCon}}, 39 | \code{\link{OR}()}, 40 | \code{\link{before}()}, 41 | \code{\link{flag}()}, 42 | \code{\link{larger_than}()}, 43 | \code{\link{older_than}()}, 44 | \code{\link{sent_before}()}, 45 | \code{\link{sent_on}()}, 46 | \code{\link{sent_since}()}, 47 | \code{\link{since}()}, 48 | \code{\link{smaller_than}()}, 49 | \code{\link{string}()}, 50 | \code{\link{younger_than}()} 51 | } 52 | \concept{custom search} 53 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Common Pipe operator} 6 | \description{ 7 | Common Pipe operator 8 | } 9 | \keyword{internal} 10 | -------------------------------------------------------------------------------- /man/sent_before.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sent-before.R 3 | \name{sent_before} 4 | \alias{sent_before} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | sent_before(date_char, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{date_char}{A \code{character string} with format "DD-Mon-YYYY", e.g. 11 | "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 12 | objects, since IMAP servers use this unusual date format.} 13 | 14 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 15 | CRITERIA". Default is \code{FALSE}.} 16 | } 17 | \value{ 18 | A search string to be used as a \code{request} parameter in 19 | \code{ImapCon$search()} function. 20 | } 21 | \description{ 22 | Criterion constructor function to be combined in a custom search statement 23 | } 24 | \examples{ 25 | \dontrun{ 26 | # select folder & search 27 | con$select_folder(name = "INBOX") 28 | # search for messages SINCE "30-Ago-2019" AND SMALLER than 512KB. 29 | res <- con$search(request = AND(sent_since(date_char = "30-Ago-2019"), 30 | smaller_than(size = 512000))) 31 | } 32 | } 33 | \seealso{ 34 | Other custom search: 35 | \code{\link{AND}()}, 36 | \code{\link{ImapCon}}, 37 | \code{\link{OR}()}, 38 | \code{\link{before}()}, 39 | \code{\link{flag}()}, 40 | \code{\link{larger_than}()}, 41 | \code{\link{older_than}()}, 42 | \code{\link{on}()}, 43 | \code{\link{sent_on}()}, 44 | \code{\link{sent_since}()}, 45 | \code{\link{since}()}, 46 | \code{\link{smaller_than}()}, 47 | \code{\link{string}()}, 48 | \code{\link{younger_than}()} 49 | } 50 | \concept{custom search} 51 | -------------------------------------------------------------------------------- /man/sent_on.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sent-on.R 3 | \name{sent_on} 4 | \alias{sent_on} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | sent_on(date_char, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{date_char}{A \code{character string} with format "DD-Mon-YYYY", e.g. 11 | "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 12 | objects, since IMAP servers use this unusual date format.} 13 | 14 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 15 | CRITERIA". Default is \code{FALSE}.} 16 | } 17 | \value{ 18 | A search string to be used as a \code{request} parameter in 19 | \code{ImapCon$search()} function. 20 | } 21 | \description{ 22 | Criterion constructor function to be combined in a custom search statement 23 | } 24 | \examples{ 25 | \dontrun{ 26 | # select folder & search 27 | con$select_folder(name = "INBOX") 28 | # search for messages SINCE "30-Ago-2019" OR LARGER than 512KB. 29 | res <- con$search(request = OR(sent_since(date_char = "30-Jun-2020"), 30 | larger_than(size = 512000))) 31 | } 32 | } 33 | \seealso{ 34 | Other custom search: 35 | \code{\link{AND}()}, 36 | \code{\link{ImapCon}}, 37 | \code{\link{OR}()}, 38 | \code{\link{before}()}, 39 | \code{\link{flag}()}, 40 | \code{\link{larger_than}()}, 41 | \code{\link{older_than}()}, 42 | \code{\link{on}()}, 43 | \code{\link{sent_before}()}, 44 | \code{\link{sent_since}()}, 45 | \code{\link{since}()}, 46 | \code{\link{smaller_than}()}, 47 | \code{\link{string}()}, 48 | \code{\link{younger_than}()} 49 | } 50 | \concept{custom search} 51 | -------------------------------------------------------------------------------- /man/sent_since.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sent-since.R 3 | \name{sent_since} 4 | \alias{sent_since} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | sent_since(date_char, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{date_char}{A \code{character string} with format "DD-Mon-YYYY", e.g. 11 | "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 12 | objects, since IMAP servers use this unusual date format.} 13 | 14 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 15 | CRITERIA". Default is \code{FALSE}.} 16 | } 17 | \value{ 18 | A search string to be used as a \code{request} parameter in 19 | \code{ImapCon$search()} function. 20 | } 21 | \description{ 22 | Criterion constructor function to be combined in a custom search statement 23 | } 24 | \examples{ 25 | \dontrun{ 26 | # select folder & search 27 | con$select_folder(name = "INBOX") 28 | # search for messages SENT SINCE "22-Mar-2020" OR containing the STRING 29 | # "congratulations" in the subject. 30 | res <- con$search(request = AND(sent_since(date_char = "22-Mar-2020"), 31 | string(expr = "congratulations", 32 | where = "SUBJECT"))) 33 | } 34 | } 35 | \seealso{ 36 | Other custom search: 37 | \code{\link{AND}()}, 38 | \code{\link{ImapCon}}, 39 | \code{\link{OR}()}, 40 | \code{\link{before}()}, 41 | \code{\link{flag}()}, 42 | \code{\link{larger_than}()}, 43 | \code{\link{older_than}()}, 44 | \code{\link{on}()}, 45 | \code{\link{sent_before}()}, 46 | \code{\link{sent_on}()}, 47 | \code{\link{since}()}, 48 | \code{\link{smaller_than}()}, 49 | \code{\link{string}()}, 50 | \code{\link{younger_than}()} 51 | } 52 | \concept{custom search} 53 | -------------------------------------------------------------------------------- /man/since.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/since.R 3 | \name{since} 4 | \alias{since} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | since(date_char, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{date_char}{A \code{character string} with format "DD-Mon-YYYY", e.g. 11 | "01-Apr-2019". We opt not to use \code{Date} or \code{POSIX*} like 12 | objects, since IMAP servers use this unusual date format.} 13 | 14 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 15 | CRITERIA". Default is \code{FALSE}.} 16 | } 17 | \value{ 18 | A search string to be used as a \code{request} parameter in 19 | \code{ImapCon$search()} function. 20 | } 21 | \description{ 22 | Criterion constructor function to be combined in a custom search statement 23 | } 24 | \examples{ 25 | \dontrun{ 26 | # select folder & search 27 | con$select_folder(name = "INBOX") 28 | # search for messages SINCE "17-Apr-2019" AND SMALLER than 512KB. 29 | res <- con$search(request = AND(since(date_char = "17-Apr-2019"), 30 | smaller_than(size = 512000))) 31 | } 32 | } 33 | \seealso{ 34 | Other custom search: 35 | \code{\link{AND}()}, 36 | \code{\link{ImapCon}}, 37 | \code{\link{OR}()}, 38 | \code{\link{before}()}, 39 | \code{\link{flag}()}, 40 | \code{\link{larger_than}()}, 41 | \code{\link{older_than}()}, 42 | \code{\link{on}()}, 43 | \code{\link{sent_before}()}, 44 | \code{\link{sent_on}()}, 45 | \code{\link{sent_since}()}, 46 | \code{\link{smaller_than}()}, 47 | \code{\link{string}()}, 48 | \code{\link{younger_than}()} 49 | } 50 | \concept{custom search} 51 | -------------------------------------------------------------------------------- /man/smaller_than.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/smaller-than.R 3 | \name{smaller_than} 4 | \alias{smaller_than} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | smaller_than(size, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{size}{An integer specifying the number of seconds to be used as 11 | search criterion.} 12 | 13 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 14 | CRITERIA". Default is \code{FALSE}.} 15 | } 16 | \description{ 17 | Criterion constructor function to be combined in a custom search statement 18 | } 19 | \examples{ 20 | \dontrun{ 21 | # select folder & search 22 | con$select_folder(name = "INBOX") 23 | # search for messages containing the string "XYZ@k-state.edu" in the 24 | # "FROM" field OR those that are SMALLER than 512KB. 25 | res <- con$search(request = OR(string(expr = "XYZ@k-state.edu", 26 | where = "FROM"), 27 | smaller_than(size = 512000))) 28 | } 29 | 30 | } 31 | \seealso{ 32 | Other custom search: 33 | \code{\link{AND}()}, 34 | \code{\link{ImapCon}}, 35 | \code{\link{OR}()}, 36 | \code{\link{before}()}, 37 | \code{\link{flag}()}, 38 | \code{\link{larger_than}()}, 39 | \code{\link{older_than}()}, 40 | \code{\link{on}()}, 41 | \code{\link{sent_before}()}, 42 | \code{\link{sent_on}()}, 43 | \code{\link{sent_since}()}, 44 | \code{\link{since}()}, 45 | \code{\link{string}()}, 46 | \code{\link{younger_than}()} 47 | } 48 | \concept{custom search} 49 | -------------------------------------------------------------------------------- /man/string.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/string.R 3 | \name{string} 4 | \alias{string} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | string(expr, where, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{expr}{A character string specifying the word or expression to search 11 | for in messages.} 12 | 13 | \item{where}{A mandatory character string specifying in which 14 | message's Section or Header Field to search for the provided string.} 15 | 16 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 17 | CRITERIA". Default is \code{FALSE}.} 18 | } 19 | \description{ 20 | Criterion constructor function to be combined in a custom search statement 21 | } 22 | \examples{ 23 | \dontrun{ 24 | # select folder & search 25 | con$select_folder(name = "INBOX") 26 | # search for messages containing the string "XYZ@k-state.edu" in the 27 | # "FROM" AND the string "@gmail.com" in the "CC" field. 28 | res <- con$search(request = AND(string(expr = "XYZ@k-state.edu", 29 | where = "FROM"), 30 | string(expr = "@gmail.com", 31 | where = "CC"))) 32 | } 33 | 34 | } 35 | \seealso{ 36 | Other custom search: 37 | \code{\link{AND}()}, 38 | \code{\link{ImapCon}}, 39 | \code{\link{OR}()}, 40 | \code{\link{before}()}, 41 | \code{\link{flag}()}, 42 | \code{\link{larger_than}()}, 43 | \code{\link{older_than}()}, 44 | \code{\link{on}()}, 45 | \code{\link{sent_before}()}, 46 | \code{\link{sent_on}()}, 47 | \code{\link{sent_since}()}, 48 | \code{\link{since}()}, 49 | \code{\link{smaller_than}()}, 50 | \code{\link{younger_than}()} 51 | } 52 | \concept{custom search} 53 | -------------------------------------------------------------------------------- /man/younger_than.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/younger-than.R 3 | \name{younger_than} 4 | \alias{younger_than} 5 | \title{Criterion constructor function to be combined in a custom search statement} 6 | \usage{ 7 | younger_than(seconds, negate = FALSE) 8 | } 9 | \arguments{ 10 | \item{seconds}{An integer specifying the number of seconds to be used as 11 | the search criterion.} 12 | 13 | \item{negate}{If \code{TRUE}, negates the search and seeks for "NOT SEARCH 14 | CRITERIA". Default is \code{FALSE}.} 15 | } 16 | \description{ 17 | Criterion constructor function to be combined in a custom search statement 18 | } 19 | \note{ 20 | To be able to use this functionality, the server must support the 21 | \code{WITHIN} capability. 22 | } 23 | \examples{ 24 | \dontrun{ 25 | # select folder & search 26 | con$select_folder(name = "INBOX") 27 | # search for messages containing the string "XYZ@k-state.edu" in the 28 | # "FROM" field AND those that are YOUNGER than 3600 seconds (1 hour). 29 | res <- con$search(request = AND(string(expr = "XYZ@k-state.edu", 30 | where = "FROM"), 31 | younger_than(seconds = 3600))) 32 | } 33 | 34 | } 35 | \seealso{ 36 | Other custom search: 37 | \code{\link{AND}()}, 38 | \code{\link{ImapCon}}, 39 | \code{\link{OR}()}, 40 | \code{\link{before}()}, 41 | \code{\link{flag}()}, 42 | \code{\link{larger_than}()}, 43 | \code{\link{older_than}()}, 44 | \code{\link{on}()}, 45 | \code{\link{sent_before}()}, 46 | \code{\link{sent_on}()}, 47 | \code{\link{sent_since}()}, 48 | \code{\link{since}()}, 49 | \code{\link{smaller_than}()}, 50 | \code{\link{string}()} 51 | } 52 | \concept{custom search} 53 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | .httr-oauth 2 | -------------------------------------------------------------------------------- /vignettes/figures/basics/attach1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/basics/attach1.png -------------------------------------------------------------------------------- /vignettes/figures/basics/attach2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/basics/attach2.png -------------------------------------------------------------------------------- /vignettes/figures/basics/fetchbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/basics/fetchbody.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step1_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step1_1.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step1_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step1_1x.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step1_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step1_2.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_1.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_1x.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_2.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_2x.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_3.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_4.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_x1.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_x2.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_x3.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_x3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_x3x.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_x4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_x4.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_x5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_x5.png -------------------------------------------------------------------------------- /vignettes/figures/xoauth/step2_x6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/allanvc/mRpostman/b8faa99d9bb340c52206eabc7cfe12c8288c871e/vignettes/figures/xoauth/step2_x6.png -------------------------------------------------------------------------------- /vignettes/xoauth2.0: -------------------------------------------------------------------------------- 1 | --- 2 | title: "IMAP OAuth2.0 authentication with mRpostman" 3 | output: 4 | rmarkdown::html_vignette: 5 | toc: yes 6 | vignette: > 7 | %\VignetteIndexEntry{Migrating code to mRpostman's R6 sintaxe} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | \usepackage[utf8]{inputenc} 10 | --- 11 | 12 | 13 | 14 | 26 | 27 | ## Introduction 28 | 29 | More and more mail providers are adopting the OAuth2.0 authentication as they preferred method. Although there may be some pain involved in the process of configuring and obtaining an access token, it is definetely a more secure way of authenticating your identity during the access. 30 | 31 | In this vignette, we will describe the process of obtaining, using and refreshing a OAuth2.0 token in order to establish a connection with the GMail IMAP server. This process will very likely be similar in the case of other mail providers, such as AOL, Yahoo, etc. 32 | 33 | The steps involved in configurating and obtaining an oauth2.0 access token can be summarized as the following: 34 | 35 | * 1) creating a new API project in the Google Account Console 36 | * 2) creating new credentials access for the project 37 | * 3) obtaining and saving the credentials 38 | * 4) using the `httr` package to retrieve... 39 | 40 | ## Step 1 - Creating a new API project 41 | 42 | Using yopur web browser, log into the page: https://console.developers.google.com/apis/. Assuming tht you don't have any pre-existent project, you should see this page: 43 | 44 | ![](vignettes/figures/xoauth/step1_1.png) 45 | 46 | Then, click on "Create New Project" 47 | 48 | On the next screen, type a name for your project. Here, we go with "mRpostman": 49 | 50 | ![]() 51 | 52 | After a few seconds, the project is created. 53 | 54 | 55 | ## Step 2 - Creating new credentials 56 | 57 | Once the project is created, we move to the credentials part. 58 | 59 | Click on "CREDENTIALS" in the menu on the left: 60 | 61 | ![]() 62 | 63 | You should see the following screen: 64 | 65 | ![]() 66 | 67 | On the menu on the top, click on "+ CREATE CREDENTIALS", then on "OAuth client ID". 68 | 69 | ![]() 70 | 71 | You should see the following screen. Click on "CONFIGURE CONSENT SCREEN". 72 | 73 | ![]() 74 | 75 | Choose "External", then click on "CREATE" 76 | 77 | ![]() 78 | 79 | In the following page, inform an app name (it can be mRpostman again): 80 | 81 | ![]() 82 | 83 | You don't need to fill more fields besides the app name. Then click on "SAVE" on the bottom of the page.. 84 | 85 | 86 | 87 | 88 | The st 89 | 90 | 91 | 92 | --------------------------------------------------------------------------------