Skip to content

Commit

Permalink
v1.1.2-CRAN
Browse files Browse the repository at this point in the history
  • Loading branch information
allanvc committed Dec 17, 2023
1 parent eb29d26 commit abd8b7a
Show file tree
Hide file tree
Showing 38 changed files with 222 additions and 134 deletions.
11 changes: 8 additions & 3 deletions DESCRIPTION
@@ -1,13 +1,18 @@
Package: mRpostman
Type: Package
Title: An IMAP Client for R
Version: 1.1.1
Date: 2023-07-27
Version: 1.1.2
Date: 2023-12-17
Authors@R: c(
person(given="Allan", family="Quadros",
role = c("aut", "cre"),
email = "allanvcq@gmail.com",
comment = c(ORCID = "0000-0003-3250-5380")))
comment = c(ORCID = "0000-0003-3250-5380")),
person(given="Paul", family="Smith",
role = c("ctb")),
person(given="Kurt", family="Hornik",
role = c("ctb"))
)
Description: An easy-to-use IMAP client that provides tools for message searching,
selective fetching of message attributes, mailbox management, attachment extraction,
and several other IMAP features, paving the way for e-mail data analysis in R.
Expand Down
10 changes: 10 additions & 0 deletions NEWS.md
@@ -1,3 +1,13 @@
## mRpostman 1.1.2 (2023-12-17 CRAN update)

### Methods & Functions

- `clean_fetch_results()`: added argument `useBytes = TRUE` to all `gsub()` calls. According to Kurt Hornik, "fetching fails using current versions of R for some contents with non-ASCII characters".

- Added bypass argument `as_is` to methods/functions `get_attachments()`, `execute_fetch_attachments()`, `fetch_attachments()`; and `as_is` functionality to `get_attachments()` and `execute_fetch_attachments` as proposed by Pauls Smith to handle non-base64 files.

---

## mRpostman 1.1.1 (2023-07-27 Github patch)

### Documentation
Expand Down
13 changes: 9 additions & 4 deletions R/R6.R
Expand Up @@ -1681,6 +1681,8 @@ ImapCon <- R6::R6Class("ImapCon",
#' command is successfully executed. Default is \code{FALSE}.
#' @param mute A \code{logical}. If \code{TRUE}, mutes the confirmation message
#' when the command is successfully executed. Default is \code{FALSE}.
#' @param as_is If \code{TRUE} then write out attachments without base64
#' decoding. Default is \code{FALSE}.
#' @note \href{#method-get_attachments}{\code{ImapCon$get_attachments()}}:
#' This method is to be used after the body or the
#' text part of one or more messages were fetched. This makes sense if the
Expand Down Expand Up @@ -1730,9 +1732,9 @@ ImapCon <- R6::R6Class("ImapCon",
#' con$get_attachments(msg_list = out)
#' }
get_attachments = function(msg_list, content_disposition = "both",
override = FALSE, mute = FALSE) {
override = FALSE, mute = FALSE, as_is = FALSE) {
out <- get_attachments_int(self, msg_list, content_disposition, override,
mute)
mute, as_is)

invisible(out)

Expand Down Expand Up @@ -1797,6 +1799,8 @@ ImapCon <- R6::R6Class("ImapCon",
#' when the command is successfully executed. Default is \code{FALSE}.
#' @param retries Number of attempts to connect and execute the command. Default
#' is \code{1}.
#' @param as_is If \code{TRUE} then write out attachments without base64
#' decoding. Default is \code{FALSE}.
#' @note \href{#method-fetch_attachments}{\code{ImapCon$fetch_attachments()}}: All
#' attachments will be stored in a folder labeled with the message id
#' inside the \code{working directory > servername > foldername}.
Expand Down Expand Up @@ -1836,9 +1840,10 @@ ImapCon <- R6::R6Class("ImapCon",
#'
#' }
fetch_attachments = function(msg_id, use_uid = FALSE, content_disposition = "both",
override = FALSE, mute = FALSE, retries = 1) {
override = FALSE, mute = FALSE, retries = 1,
as_is = FALSE) {
out <- fetch_attachments_int(self, msg_id, use_uid, content_disposition,
override, mute, retries)
override, mute, retries, as_is)

invisible(out)

Expand Down
16 changes: 8 additions & 8 deletions R/clean-fetch-results.R
Expand Up @@ -6,24 +6,24 @@ clean_fetch_results <- function(msg_text, metadata_attribute = NULL, attachment_

pattern1 = "\\* \\d+ FETCH.*BODY.*\\{\\d+\\}\r\n"
# result <- stringr::str_remove(string = msg_text, pattern = pattern1)
result <- gsub(pattern1, "", msg_text, ignore.case = TRUE)
result <- gsub(pattern1, "", msg_text, ignore.case = TRUE, useBytes = TRUE)

pattern2 = "\\)\r\n[A-Z]\\d+ OK Success\r\n"
# result <- stringr::str_remove(string = result, pattern = pattern2)
result <- gsub(pattern2, "", result, ignore.case = TRUE)
result <- gsub(pattern2, "", result, ignore.case = TRUE, useBytes = TRUE)

pattern3 = "\\)\r\n[A-Z]\\d+ OK FETCH completed.\r\n" #MS Exchange and yandex
# result <- stringr::str_remove(string = result, pattern = pattern3)
result <- gsub(pattern3, "", result, ignore.case = TRUE)
result <- gsub(pattern3, "", result, ignore.case = TRUE, useBytes = TRUE)

# attachments
pattern4 = "\\)\r\n[A-Z]\\d+ OK FETCH completed\r\n" #MS Exchange
# result <- stringr::str_remove(string = result, pattern = pattern3)
result <- gsub(pattern4, "", result, ignore.case = TRUE)
result <- gsub(pattern4, "", result, ignore.case = TRUE, useBytes = TRUE)

pattern5 = "\r\n UID \\d+ FLAGS \\(.*\\)" #MS Exchange # important for attachments fetching
# result <- stringr::str_remove(string = result, pattern = pattern3)
result <- gsub(pattern5, "", result, ignore.case = TRUE)
result <- gsub(pattern5, "", result, ignore.case = TRUE, useBytes = TRUE)

# pattern5 = "\r\n \\d+ FLAGS \\(.*\\)" #MS Exchange
# # result <- stringr::str_remove(string = result, pattern = pattern3)
Expand All @@ -33,15 +33,15 @@ clean_fetch_results <- function(msg_text, metadata_attribute = NULL, attachment_
if (!is.null(metadata_attribute) && (!any(metadata_attribute == "UID" || metadata_attribute == "uid"))) {
pattern6 = "UID \\d+$| UID \\d+$"
# result <- stringr::str_remove(string = result, pattern = pattern2)
result <- gsub(pattern6, "", result, ignore.case = TRUE)
result <- gsub(pattern6, "", result, ignore.case = TRUE, useBytes = TRUE)
}

pattern7 = "^\\* \\d+ FETCH \\(" # important for fetch_metadata()
result <- gsub(pattern7, "", result, ignore.case = TRUE)
result <- gsub(pattern7, "", result, ignore.case = TRUE, useBytes = TRUE)

if (isTRUE(attachment_fetch)) { # in order to not have problem with fetcH_body/text + get_attachments() combo
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
result <- gsub(pattern8, "", result, ignore.case = TRUE)
result <- gsub(pattern8, "", result, ignore.case = TRUE, useBytes = TRUE)
}


Expand Down
64 changes: 35 additions & 29 deletions R/execute-attachment-fetch.R
Expand Up @@ -19,10 +19,12 @@
#' name, which will be uses to create a local folder.
#' @param retries Number of attempts to connect and execute the command. Default
#' is \code{1}.
#' @param as_is If \code{TRUE} then write out attachments without base64
#' decoding. Default is \code{FALSE}.
#' @noRd
execute_attachment_fetch <- function(self, id, id_folder, df_meta_to_fetch, fetch_request,
folder_clean, content_disposition,
override, retries) {
override, retries, as_is) {


url <- self$con_params$url
Expand Down Expand Up @@ -183,34 +185,38 @@ execute_attachment_fetch <- function(self, id, id_folder, df_meta_to_fetch, fetc
# # base64 encoding
# if (encodings[i] == "base64") {

# saving attachments
# thank's to:
# https://stackoverflow.com/questions/36708191/convert-base64-to-png-jpeg-file-in-r
# writing binary file
temp_bin_name <- paste0(sample(letters, 4), sample(0:9, 4), collapse="")
conn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"wb")
writeBin(attachment, conn)
close(conn)
# decoding from BIN to the appropriate file extension
inconn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"rb")
outconn <- file(complete_path_with_filename,"wb")

# base64 text decoding
tryCatch({
base64enc::base64decode(what=inconn, output=outconn)
}, error = function(e) {
warning(paste0("Base64 text decoding failed for", df_meta_to_fetch$filenames[i]))
})

close(inconn)
close(outconn)

unlink(paste0(complete_path, "/", temp_bin_name, ".bin")) # deleting binary file
# From unlink() help: Not deleting a non-existent file is not a failure
# we don't need a tryCatch()

# }

if (as_is) {
## write out the file directly to the final file name
writeBin(attachment, complete_path_with_filename)
} else {
# saving attachments
# thank's to:
# https://stackoverflow.com/questions/36708191/convert-base64-to-png-jpeg-file-in-r
# writing binary file
temp_bin_name <- paste0(sample(letters, 4), sample(0:9, 4), collapse="")
conn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"wb")
writeBin(attachment, conn)
close(conn)
# decoding from BIN to the appropriate file extension
inconn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"rb")
outconn <- file(complete_path_with_filename,"wb")

# base64 text decoding
tryCatch({
base64enc::base64decode(what=inconn, output=outconn)
}, error = function(e) {
warning(paste0("Base64 text decoding failed for", df_meta_to_fetch$filenames[i]))
})

close(inconn)
close(outconn)

unlink(paste0(complete_path, "/", temp_bin_name, ".bin")) # deleting binary file
# From unlink() help: Not deleting a non-existent file is not a failure
# we don't need a tryCatch()

# }
}
}


Expand Down
6 changes: 4 additions & 2 deletions R/fetch-attachments-int.R
Expand Up @@ -17,9 +17,11 @@
#' containing the same name in the local directory. Default is \code{FALSE}.
#' @param mute A \code{logical}. If \code{TRUE}, mutes the confirmation message
#' when the command is successfully executed. Default is \code{FALSE}.
#' @param as_is If \code{TRUE} then write out attachments without base64
#' decoding. Default is \code{FALSE}.
#' @noRd
fetch_attachments_int <- function(self, msg_id, use_uid, content_disposition, override,
mute, retries) {
mute, retries, as_is) {

#check
check_args(msg_id = msg_id, use_uid = use_uid, content_disposition = content_disposition,
Expand Down Expand Up @@ -104,7 +106,7 @@ fetch_attachments_int <- function(self, msg_id, use_uid, content_disposition, ov
if (nrow(df_meta_to_fetch) > 0) {
execute_attachment_fetch(self, id, id_folder, df_meta_to_fetch, fetch_request,
folder_clean, content_disposition,
override, retries)
override, retries, as_is)
} # if not, do nothing

} #if not, do nothing
Expand Down
65 changes: 39 additions & 26 deletions R/get-attachments-int.R
Expand Up @@ -10,9 +10,11 @@
#' containing the same name in the local directory. Default is \code{FALSE}.
#' @param mute A \code{logical}. If \code{TRUE}, mutes the confirmation message
#' when the command is successfully executed. Default is \code{FALSE}.
#' @param as_is If \code{TRUE} then write out attachments without base64
#' decoding. Default is \code{FALSE}.
#' @noRd
get_attachments_int <- function(self, msg_list, content_disposition, override,
mute) {
mute, as_is) {

# previous folder selection checking
if (is.na(self$con_params$folder)) {
Expand Down Expand Up @@ -190,31 +192,42 @@ get_attachments_int <- function(self, msg_list, content_disposition, override,
# complete_path_with_filename <- serialize_filename(
# prefix = paste0(complete_path, "/", filenames[i]))

# saving attachments
# thank's to:
# https://stackoverflow.com/questions/36708191/convert-base64-to-png-jpeg-file-in-r
# writing binary file
temp_bin_name <- paste0(sample(letters, 4), sample(0:9, 4), collapse="")
conn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"wb")
writeBin(attachments_text[i], conn)
close(conn)
# decoding from BIN to the appropriate file extension
inconn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"rb")
outconn <- file(complete_path_with_filename,"wb")

# base64 text decoding
tryCatch({
base64enc::base64decode(what=inconn, output=outconn)
}, error = function(e) {
warning(paste0("Base64 text decoding failed for", adjusted_filenames[i]))
})

close(inconn)
close(outconn)

unlink(paste0(complete_path, "/", temp_bin_name, ".bin")) # deleting binary file
# From unlink() help: Not deleting a non-existent file is not a failure
# we don't need a tryCatch()
# bypass proposed by @waternumbers at https://github.com/allanvc/mRpostman/pull/8
# It was originally proposed to fecth_attachments(), but ...
# I incorporated it in get_attachments() as well
if (as_is) {
## write out the file directly to the final file name
writeBin(attachments_text[i], complete_path_with_filename)
} else {
# saving attachments
# thank's to:
# https://stackoverflow.com/questions/36708191/convert-base64-to-png-jpeg-file-in-r
# writing binary file
temp_bin_name <- paste0(sample(letters, 4), sample(0:9, 4), collapse="")
conn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"wb")
writeBin(attachments_text[i], conn)
close(conn)
# decoding from BIN to the appropriate file extension
inconn <- file(paste0(complete_path, "/", temp_bin_name, ".bin"),"rb")
outconn <- file(complete_path_with_filename,"wb")

# base64 text decoding
tryCatch({
base64enc::base64decode(what=inconn, output=outconn)
}, error = function(e) {
warning(paste0("Base64 text decoding failed for", adjusted_filenames[i]))
})

close(inconn)
close(outconn)

unlink(paste0(complete_path, "/", temp_bin_name, ".bin")) # deleting binary file
# From unlink() help: Not deleting a non-existent file is not a failure
# we don't need a tryCatch()


}


}

Expand Down
4 changes: 2 additions & 2 deletions docs/articles/basics.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions docs/articles/code_migration.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/articles/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions docs/articles/xoauth2.0.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion docs/authors.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit abd8b7a

Please sign in to comment.